From 026efcd174cdb1b1d0fece9611dbae358de48387 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Wed, 24 Aug 2011 14:08:25 -0400 Subject: Updated FlavorsXMLSerialization tests to use etree and validation instead of minidom --- nova/tests/api/openstack/test_flavors.py | 180 ++++++++++++++----------------- 1 file changed, 79 insertions(+), 101 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_flavors.py b/nova/tests/api/openstack/test_flavors.py index 812bece42..ea5038b39 100644 --- a/nova/tests/api/openstack/test_flavors.py +++ b/nova/tests/api/openstack/test_flavors.py @@ -17,16 +17,21 @@ import json import webob -import xml.dom.minidom as minidom +from lxml import etree from nova.api.openstack import flavors import nova.db.api from nova import exception from nova import test +from nova.api.openstack import xmlutil from nova.tests.api.openstack import fakes from nova import wsgi +NS = "{http://docs.openstack.org/compute/api/v1.1}" +ATOMNS = "{http://www.w3.org/2005/Atom}" + + def stub_flavor(flavorid, name, memory_mb="256", local_gb="10"): return { "flavorid": str(flavorid), @@ -265,7 +270,7 @@ class FlavorsXMLSerializationTest(test.TestCase): def test_show(self): serializer = flavors.FlavorXMLSerializer() - input = { + fixture = { "flavor": { "id": "12", "name": "asdf", @@ -284,29 +289,25 @@ class FlavorsXMLSerializationTest(test.TestCase): }, } - output = serializer.serialize(input, 'show') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(""" - - - - - """.replace(" ", "")) - - self.assertEqual(expected.toxml(), actual.toxml()) + output = serializer.serialize(fixture, 'show') + print output + root = etree.XML(output) + xmlutil.validate_schema(root, 'flavor') + flavor_dict = fixture['flavor'] + + for key in ['name', 'id', 'ram', 'disk']: + self.assertEqual(root.get(key), str(flavor_dict[key])) + + link_nodes = root.findall('{0}link'.format(ATOMNS)) + self.assertEqual(len(link_nodes), 2) + for i, link in enumerate(flavor_dict['links']): + for key, value in link.items(): + self.assertEqual(link_nodes[i].get(key), value) def test_show_handles_integers(self): serializer = flavors.FlavorXMLSerializer() - input = { + fixture = { "flavor": { "id": 12, "name": "asdf", @@ -325,29 +326,25 @@ class FlavorsXMLSerializationTest(test.TestCase): }, } - output = serializer.serialize(input, 'show') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(""" - - - - - """.replace(" ", "")) - - self.assertEqual(expected.toxml(), actual.toxml()) + output = serializer.serialize(fixture, 'show') + print output + root = etree.XML(output) + xmlutil.validate_schema(root, 'flavor') + flavor_dict = fixture['flavor'] + + for key in ['name', 'id', 'ram', 'disk']: + self.assertEqual(root.get(key), str(flavor_dict[key])) + + link_nodes = root.findall('{0}link'.format(ATOMNS)) + self.assertEqual(len(link_nodes), 2) + for i, link in enumerate(flavor_dict['links']): + for key, value in link.items(): + self.assertEqual(link_nodes[i].get(key), value) def test_detail(self): serializer = flavors.FlavorXMLSerializer() - input = { + fixture = { "flavors": [ { "id": "23", @@ -383,39 +380,28 @@ class FlavorsXMLSerializationTest(test.TestCase): ], } - output = serializer.serialize(input, 'detail') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(""" - - - - - - - - - - - """.replace(" ", "") % locals()) - - self.assertEqual(expected.toxml(), actual.toxml()) + output = serializer.serialize(fixture, 'detail') + print output + root = etree.XML(output) + xmlutil.validate_schema(root, 'flavors') + flavor_elems = root.findall('{0}flavor'.format(NS)) + self.assertEqual(len(flavor_elems), 2) + for i, flavor_elem in enumerate(flavor_elems): + flavor_dict = fixture['flavors'][i] + + for key in ['name', 'id', 'ram', 'disk']: + self.assertEqual(flavor_elem.get(key), str(flavor_dict[key])) + + link_nodes = flavor_elem.findall('{0}link'.format(ATOMNS)) + self.assertEqual(len(link_nodes), 2) + for i, link in enumerate(flavor_dict['links']): + for key, value in link.items(): + self.assertEqual(link_nodes[i].get(key), value) def test_index(self): serializer = flavors.FlavorXMLSerializer() - input = { + fixture = { "flavors": [ { "id": "23", @@ -451,42 +437,34 @@ class FlavorsXMLSerializationTest(test.TestCase): ], } - output = serializer.serialize(input, 'index') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(""" - - - - - - - - - - - """.replace(" ", "") % locals()) - - self.assertEqual(expected.toxml(), actual.toxml()) + output = serializer.serialize(fixture, 'index') + print output + root = etree.XML(output) + xmlutil.validate_schema(root, 'flavors_index') + flavor_elems = root.findall('{0}flavor'.format(NS)) + self.assertEqual(len(flavor_elems), 2) + for i, flavor_elem in enumerate(flavor_elems): + flavor_dict = fixture['flavors'][i] + + for key in ['name', 'id']: + self.assertEqual(flavor_elem.get(key), str(flavor_dict[key])) + + link_nodes = flavor_elem.findall('{0}link'.format(ATOMNS)) + self.assertEqual(len(link_nodes), 2) + for i, link in enumerate(flavor_dict['links']): + for key, value in link.items(): + self.assertEqual(link_nodes[i].get(key), value) def test_index_empty(self): serializer = flavors.FlavorXMLSerializer() - input = { + fixture = { "flavors": [], } - output = serializer.serialize(input, 'index') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(""" - - """.replace(" ", "") % locals()) - - self.assertEqual(expected.toxml(), actual.toxml()) + output = serializer.serialize(fixture, 'index') + print output + root = etree.XML(output) + xmlutil.validate_schema(root, 'flavors_index') + flavor_elems = root.findall('{0}flavor'.format(NS)) + self.assertEqual(len(flavor_elems), 0) -- cgit From 08981ee7228aa0e4b68ec8e9016ef68b987a3ac3 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Wed, 24 Aug 2011 16:41:26 -0400 Subject: Updated ImageXMLSerialization tests to use etree instead of minidom Fixed incorrect server entity ids in tests --- nova/tests/api/openstack/test_images.py | 347 +++++++++++++++----------------- 1 file changed, 162 insertions(+), 185 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_images.py b/nova/tests/api/openstack/test_images.py index 2a7cfc382..145cf527c 100644 --- a/nova/tests/api/openstack/test_images.py +++ b/nova/tests/api/openstack/test_images.py @@ -23,6 +23,7 @@ and as a WSGI layer import copy import json import os +from lxml import etree import shutil import tempfile import xml.dom.minidom as minidom @@ -38,9 +39,14 @@ from nova import test from nova import utils import nova.api.openstack from nova.api.openstack import images +from nova.api.openstack import xmlutil from nova.tests.api.openstack import fakes +NS = "{http://docs.openstack.org/compute/api/v1.1}" +ATOMNS = "{http://www.w3.org/2005/Atom}" + + class _BaseImageServiceTests(test.TestCase): """Tasks to test for all image services""" @@ -1144,7 +1150,7 @@ class ImageXMLSerializationTest(test.TestCase): 'status': 'ACTIVE', 'progress': 80, 'server': { - 'id': 1, + 'id': '1', 'links': [ { 'href': self.SERVER_HREF, @@ -1173,37 +1179,35 @@ class ImageXMLSerializationTest(test.TestCase): } output = serializer.serialize(fixture, 'show') - actual = minidom.parseString(output.replace(" ", "")) - - expected_server_href = self.SERVER_HREF - expected_server_bookmark = self.SERVER_BOOKMARK - expected_href = self.IMAGE_HREF % 1 - expected_bookmark = self.IMAGE_BOOKMARK % 1 - expected_now = self.TIMESTAMP - expected = minidom.parseString(""" - - - - - - - - value1 - - - - - - """.replace(" ", "") % (locals())) - - self.assertEqual(expected.toxml(), actual.toxml()) + print output + root = etree.XML(output) + xmlutil.validate_schema(root, 'image') + image_dict = fixture['image'] + + for key in ['name', 'id', 'updated', 'created', 'status', 'progress']: + self.assertEqual(root.get(key), str(image_dict[key])) + + link_nodes = root.findall('{0}link'.format(ATOMNS)) + self.assertEqual(len(link_nodes), 2) + for i, link in enumerate(image_dict['links']): + for key, value in link.items(): + self.assertEqual(link_nodes[i].get(key), value) + + metadata_root = root.find('{0}metadata'.format(NS)) + metadata_elems = metadata_root.findall('{0}meta'.format(NS)) + self.assertEqual(len(metadata_elems), 1) + for i, metadata_elem in enumerate(metadata_elems): + (meta_key, meta_value) = image_dict['metadata'].items()[i] + self.assertEqual(str(metadata_elem.get('key')), str(meta_key)) + self.assertEqual(str(metadata_elem.text).strip(), str(meta_value)) + + server_root = root.find('{0}server'.format(NS)) + self.assertEqual(server_root.get('id'), image_dict['server']['id']) + link_nodes = server_root.findall('{0}link'.format(ATOMNS)) + self.assertEqual(len(link_nodes), 2) + for i, link in enumerate(image_dict['server']['links']): + for key, value in link.items(): + self.assertEqual(link_nodes[i].get(key), value) def test_show_zero_metadata(self): serializer = images.ImageXMLSerializer() @@ -1216,7 +1220,7 @@ class ImageXMLSerializationTest(test.TestCase): 'updated': self.TIMESTAMP, 'status': 'ACTIVE', 'server': { - 'id': 1, + 'id': '1', 'links': [ { 'href': self.SERVER_HREF, @@ -1243,31 +1247,31 @@ class ImageXMLSerializationTest(test.TestCase): } output = serializer.serialize(fixture, 'show') - actual = minidom.parseString(output.replace(" ", "")) - - expected_server_href = self.SERVER_HREF - expected_server_bookmark = self.SERVER_BOOKMARK - expected_href = self.IMAGE_HREF % 1 - expected_bookmark = self.IMAGE_BOOKMARK % 1 - expected_now = self.TIMESTAMP - expected = minidom.parseString(""" - - - - - - - - - """.replace(" ", "") % (locals())) - - self.assertEqual(expected.toxml(), actual.toxml()) + print output + root = etree.XML(output) + xmlutil.validate_schema(root, 'image') + image_dict = fixture['image'] + + for key in ['name', 'id', 'updated', 'created', 'status']: + self.assertEqual(root.get(key), str(image_dict[key])) + + link_nodes = root.findall('{0}link'.format(ATOMNS)) + self.assertEqual(len(link_nodes), 2) + for i, link in enumerate(image_dict['links']): + for key, value in link.items(): + self.assertEqual(link_nodes[i].get(key), value) + + metadata_root = root.find('{0}metadata'.format(NS)) + meta_nodes = root.findall('{0}meta'.format(ATOMNS)) + self.assertEqual(len(meta_nodes), 0) + + server_root = root.find('{0}server'.format(NS)) + self.assertEqual(server_root.get('id'), image_dict['server']['id']) + link_nodes = server_root.findall('{0}link'.format(ATOMNS)) + self.assertEqual(len(link_nodes), 2) + for i, link in enumerate(image_dict['server']['links']): + for key, value in link.items(): + self.assertEqual(link_nodes[i].get(key), value) def test_show_image_no_metadata_key(self): serializer = images.ImageXMLSerializer() @@ -1280,7 +1284,7 @@ class ImageXMLSerializationTest(test.TestCase): 'updated': self.TIMESTAMP, 'status': 'ACTIVE', 'server': { - 'id': 1, + 'id': '1', 'links': [ { 'href': self.SERVER_HREF, @@ -1306,31 +1310,31 @@ class ImageXMLSerializationTest(test.TestCase): } output = serializer.serialize(fixture, 'show') - actual = minidom.parseString(output.replace(" ", "")) - - expected_server_href = self.SERVER_HREF - expected_server_bookmark = self.SERVER_BOOKMARK - expected_href = self.IMAGE_HREF % 1 - expected_bookmark = self.IMAGE_BOOKMARK % 1 - expected_now = self.TIMESTAMP - expected = minidom.parseString(""" - - - - - - - - - """.replace(" ", "") % (locals())) - - self.assertEqual(expected.toxml(), actual.toxml()) + print output + root = etree.XML(output) + xmlutil.validate_schema(root, 'image') + image_dict = fixture['image'] + + for key in ['name', 'id', 'updated', 'created', 'status']: + self.assertEqual(root.get(key), str(image_dict[key])) + + link_nodes = root.findall('{0}link'.format(ATOMNS)) + self.assertEqual(len(link_nodes), 2) + for i, link in enumerate(image_dict['links']): + for key, value in link.items(): + self.assertEqual(link_nodes[i].get(key), value) + + metadata_root = root.find('{0}metadata'.format(NS)) + meta_nodes = root.findall('{0}meta'.format(ATOMNS)) + self.assertEqual(len(meta_nodes), 0) + + server_root = root.find('{0}server'.format(NS)) + self.assertEqual(server_root.get('id'), image_dict['server']['id']) + link_nodes = server_root.findall('{0}link'.format(ATOMNS)) + self.assertEqual(len(link_nodes), 2) + for i, link in enumerate(image_dict['server']['links']): + for key, value in link.items(): + self.assertEqual(link_nodes[i].get(key), value) def test_show_no_server(self): serializer = images.ImageXMLSerializer() @@ -1359,30 +1363,30 @@ class ImageXMLSerializationTest(test.TestCase): } output = serializer.serialize(fixture, 'show') - actual = minidom.parseString(output.replace(" ", "")) - - expected_href = self.IMAGE_HREF % 1 - expected_bookmark = self.IMAGE_BOOKMARK % 1 - expected_now = self.TIMESTAMP - expected = minidom.parseString(""" - - - - value1 - - - - - - """.replace(" ", "") % (locals())) - - self.assertEqual(expected.toxml(), actual.toxml()) + print output + root = etree.XML(output) + xmlutil.validate_schema(root, 'image') + image_dict = fixture['image'] + + for key in ['name', 'id', 'updated', 'created', 'status']: + self.assertEqual(root.get(key), str(image_dict[key])) + + link_nodes = root.findall('{0}link'.format(ATOMNS)) + self.assertEqual(len(link_nodes), 2) + for i, link in enumerate(image_dict['links']): + for key, value in link.items(): + self.assertEqual(link_nodes[i].get(key), value) + + metadata_root = root.find('{0}metadata'.format(NS)) + metadata_elems = metadata_root.findall('{0}meta'.format(NS)) + self.assertEqual(len(metadata_elems), 1) + for i, metadata_elem in enumerate(metadata_elems): + (meta_key, meta_value) = image_dict['metadata'].items()[i] + self.assertEqual(str(metadata_elem.get('key')), str(meta_key)) + self.assertEqual(str(metadata_elem.text).strip(), str(meta_value)) + + server_root = root.find('{0}server'.format(NS)) + self.assertEqual(server_root, None) def test_index(self): serializer = images.ImageXMLSerializer() @@ -1397,6 +1401,10 @@ class ImageXMLSerializationTest(test.TestCase): 'href': self.IMAGE_HREF % 1, 'rel': 'self', }, + { + 'href': self.IMAGE_BOOKMARK % 1, + 'rel': 'bookmark', + }, ], }, { @@ -1407,35 +1415,32 @@ class ImageXMLSerializationTest(test.TestCase): 'href': self.IMAGE_HREF % 2, 'rel': 'self', }, + { + 'href': self.IMAGE_BOOKMARK % 2, + 'rel': 'bookmark', + }, ], }, ] } output = serializer.serialize(fixture, 'index') - actual = minidom.parseString(output.replace(" ", "")) - - expected_server_href = self.SERVER_HREF - expected_server_bookmark = self.SERVER_BOOKMARK - expected_href = self.IMAGE_HREF % 1 - expected_bookmark = self.IMAGE_BOOKMARK % 1 - expected_href_two = self.IMAGE_HREF % 2 - expected_bookmark_two = self.IMAGE_BOOKMARK % 2 - expected_now = self.TIMESTAMP - expected = minidom.parseString(""" - - - - - - - - - """.replace(" ", "") % (locals())) - - self.assertEqual(expected.toxml(), actual.toxml()) + print output + root = etree.XML(output) + xmlutil.validate_schema(root, 'images_index') + image_elems = root.findall('{0}image'.format(NS)) + self.assertEqual(len(image_elems), 2) + for i, image_elem in enumerate(image_elems): + image_dict = fixture['images'][i] + + for key in ['name', 'id']: + self.assertEqual(image_elem.get(key), str(image_dict[key])) + + link_nodes = image_elem.findall('{0}link'.format(ATOMNS)) + self.assertEqual(len(link_nodes), 2) + for i, link in enumerate(image_dict['links']): + for key, value in link.items(): + self.assertEqual(link_nodes[i].get(key), value) def test_index_zero_images(self): serializer = images.ImageXMLSerializer() @@ -1445,15 +1450,11 @@ class ImageXMLSerializationTest(test.TestCase): } output = serializer.serialize(fixtures, 'index') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(""" - - """.replace(" ", "") % (locals())) - - self.assertEqual(expected.toxml(), actual.toxml()) + print output + root = etree.XML(output) + xmlutil.validate_schema(root, 'images_index') + image_elems = root.findall('{0}image'.format(NS)) + self.assertEqual(len(image_elems), 0) def test_detail(self): serializer = images.ImageXMLSerializer() @@ -1467,7 +1468,7 @@ class ImageXMLSerializationTest(test.TestCase): 'updated': self.TIMESTAMP, 'status': 'ACTIVE', 'server': { - 'id': 1, + 'id': '1', 'links': [ { 'href': self.SERVER_HREF, @@ -1491,7 +1492,7 @@ class ImageXMLSerializationTest(test.TestCase): ], }, { - 'id': 2, + 'id': '2', 'name': 'Image2', 'created': self.TIMESTAMP, 'updated': self.TIMESTAMP, @@ -1515,46 +1516,22 @@ class ImageXMLSerializationTest(test.TestCase): } output = serializer.serialize(fixture, 'detail') - actual = minidom.parseString(output.replace(" ", "")) - - expected_server_href = self.SERVER_HREF - expected_server_bookmark = self.SERVER_BOOKMARK - expected_href = self.IMAGE_HREF % 1 - expected_bookmark = self.IMAGE_BOOKMARK % 1 - expected_href_two = self.IMAGE_HREF % 2 - expected_bookmark_two = self.IMAGE_BOOKMARK % 2 - expected_now = self.TIMESTAMP - expected = minidom.parseString(""" - - - - - - - - - - - - - value1 - - - - - - - """.replace(" ", "") % (locals())) - - self.assertEqual(expected.toxml(), actual.toxml()) + print output + root = etree.XML(output) + xmlutil.validate_schema(root, 'images') + image_elems = root.findall('{0}image'.format(NS)) + self.assertEqual(len(image_elems), 2) + for i, image_elem in enumerate(image_elems): + image_dict = fixture['images'][i] + + for key in ['name', 'id', 'updated', 'created', 'status']: + self.assertEqual(image_elem.get(key), str(image_dict[key])) + + link_nodes = image_elem.findall('{0}link'.format(ATOMNS)) + self.assertEqual(len(link_nodes), 2) + for i, link in enumerate(image_dict['links']): + for key, value in link.items(): + self.assertEqual(link_nodes[i].get(key), value) + + metadata_root = image_elem.find('{0}metadata'.format(NS)) + metadata_elems = metadata_root.findall('{0}meta'.format(NS)) -- cgit From 48b2de98d002a3f7dac03d29696e4c37ed4f983f Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 25 Aug 2011 12:05:53 -0400 Subject: Added schemas Updated metadata tests to use etree instead of minidom --- nova/tests/api/openstack/test_common.py | 122 ++++++++++++++++++-------------- 1 file changed, 68 insertions(+), 54 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_common.py b/nova/tests/api/openstack/test_common.py index b422bc4d1..2e5bf08fa 100644 --- a/nova/tests/api/openstack/test_common.py +++ b/nova/tests/api/openstack/test_common.py @@ -19,6 +19,7 @@ Test suites for 'common' code used throughout the OpenStack HTTP API. """ +from lxml import etree import webob.exc import xml.dom.minidom as minidom @@ -26,6 +27,11 @@ from webob import Request from nova import test from nova.api.openstack import common +from nova.api.openstack import xmlutil + + +NS = "{http://docs.openstack.org/compute/api/v1.1}" +ATOMNS = "{http://www.w3.org/2005/Atom}" class LimiterTest(test.TestCase): @@ -323,16 +329,16 @@ class MetadataXMLSerializationTest(test.TestCase): }, } output = serializer.serialize(fixture, 'index') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(""" - - four - two - - """.replace(" ", "").replace("\n", "")) - - self.assertEqual(expected.toxml(), actual.toxml()) + print output + root = etree.XML(output) + xmlutil.validate_schema(root, 'metadata') + metadata_dict = fixture['metadata'] + metadata_elems = root.findall('{0}meta'.format(NS)) + self.assertEqual(len(metadata_elems), 2) + for i, metadata_elem in enumerate(metadata_elems): + (meta_key, meta_value) = metadata_dict.items()[i] + self.assertEqual(str(metadata_elem.get('key')), str(meta_key)) + self.assertEqual(str(metadata_elem.text).strip(), str(meta_value)) def test_index_null(self): serializer = common.MetadataXMLSerializer() @@ -342,15 +348,16 @@ class MetadataXMLSerializationTest(test.TestCase): }, } output = serializer.serialize(fixture, 'index') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(""" - - None - - """.replace(" ", "").replace("\n", "")) - - self.assertEqual(expected.toxml(), actual.toxml()) + print output + root = etree.XML(output) + xmlutil.validate_schema(root, 'metadata') + metadata_dict = fixture['metadata'] + metadata_elems = root.findall('{0}meta'.format(NS)) + self.assertEqual(len(metadata_elems), 1) + for i, metadata_elem in enumerate(metadata_elems): + (meta_key, meta_value) = metadata_dict.items()[i] + self.assertEqual(str(metadata_elem.get('key')), str(meta_key)) + self.assertEqual(str(metadata_elem.text).strip(), str(meta_value)) def test_index_unicode(self): serializer = common.MetadataXMLSerializer() @@ -360,15 +367,16 @@ class MetadataXMLSerializationTest(test.TestCase): }, } output = serializer.serialize(fixture, 'index') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(u""" - - Jos\xe9 - - """.encode("UTF-8").replace(" ", "").replace("\n", "")) - - self.assertEqual(expected.toxml(), actual.toxml()) + print output + root = etree.XML(output) + xmlutil.validate_schema(root, 'metadata') + metadata_dict = fixture['metadata'] + metadata_elems = root.findall('{0}meta'.format(NS)) + self.assertEqual(len(metadata_elems), 1) + for i, metadata_elem in enumerate(metadata_elems): + (meta_key, meta_value) = metadata_dict.items()[i] + self.assertEqual(str(metadata_elem.get('key')), str(meta_key)) + self.assertEqual(metadata_elem.text.strip(), meta_value) def test_show(self): serializer = common.MetadataXMLSerializer() @@ -378,14 +386,12 @@ class MetadataXMLSerializationTest(test.TestCase): }, } output = serializer.serialize(fixture, 'show') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(""" - two - """.replace(" ", "").replace("\n", "")) - - self.assertEqual(expected.toxml(), actual.toxml()) + print output + root = etree.XML(output) + meta_dict = fixture['meta'] + (meta_key, meta_value) = meta_dict.items()[0] + self.assertEqual(str(root.get('key')), str(meta_key)) + self.assertEqual(root.text.strip(), meta_value) def test_update_all(self): serializer = common.MetadataXMLSerializer() @@ -396,16 +402,16 @@ class MetadataXMLSerializationTest(test.TestCase): }, } output = serializer.serialize(fixture, 'update_all') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(""" - - value6 - value4 - - """.replace(" ", "").replace("\n", "")) - - self.assertEqual(expected.toxml(), actual.toxml()) + print output + root = etree.XML(output) + xmlutil.validate_schema(root, 'metadata') + metadata_dict = fixture['metadata'] + metadata_elems = root.findall('{0}meta'.format(NS)) + self.assertEqual(len(metadata_elems), 2) + for i, metadata_elem in enumerate(metadata_elems): + (meta_key, meta_value) = metadata_dict.items()[i] + self.assertEqual(str(metadata_elem.get('key')), str(meta_key)) + self.assertEqual(str(metadata_elem.text).strip(), str(meta_value)) def test_update_item(self): serializer = common.MetadataXMLSerializer() @@ -415,14 +421,12 @@ class MetadataXMLSerializationTest(test.TestCase): }, } output = serializer.serialize(fixture, 'update') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(""" - two - """.replace(" ", "").replace("\n", "")) - - self.assertEqual(expected.toxml(), actual.toxml()) + print output + root = etree.XML(output) + meta_dict = fixture['meta'] + (meta_key, meta_value) = meta_dict.items()[0] + self.assertEqual(str(root.get('key')), str(meta_key)) + self.assertEqual(root.text.strip(), meta_value) def test_create(self): serializer = common.MetadataXMLSerializer() @@ -434,6 +438,16 @@ class MetadataXMLSerializationTest(test.TestCase): }, } output = serializer.serialize(fixture, 'create') + print output + root = etree.XML(output) + xmlutil.validate_schema(root, 'metadata') + metadata_dict = fixture['metadata'] + metadata_elems = root.findall('{0}meta'.format(NS)) + self.assertEqual(len(metadata_elems), 3) + for i, metadata_elem in enumerate(metadata_elems): + (meta_key, meta_value) = metadata_dict.items()[i] + self.assertEqual(str(metadata_elem.get('key')), str(meta_key)) + self.assertEqual(str(metadata_elem.text).strip(), str(meta_value)) actual = minidom.parseString(output.replace(" ", "")) expected = minidom.parseString(""" -- cgit From bed249069e2770d1248ab9ef89751c15be8a13d6 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 25 Aug 2011 15:12:02 -0400 Subject: updated addresses xml serialization tests to use etree instead of minidom --- nova/tests/api/openstack/test_servers.py | 54 ++++++++++++++++---------------- 1 file changed, 27 insertions(+), 27 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 3559e6de5..0c816f965 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -3171,17 +3171,17 @@ class TestAddressesXMLSerialization(test.TestCase): ], } output = self.serializer.serialize(fixture, 'show') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(""" - - - - - """.replace(" ", "")) - - self.assertEqual(expected.toxml(), actual.toxml()) + print output + root = etree.XML(output) + network = fixture['network_2'] + self.assertEqual(str(root.get('id')), 'network_2') + ip_elems = root.findall('{0}ip'.format(NS)) + for z, ip_elem in enumerate(ip_elems): + ip = network[z] + self.assertEqual(str(ip_elem.get('version')), + str(ip['version'])) + self.assertEqual(str(ip_elem.get('addr')), + str(ip['addr'])) def test_index(self): fixture = { @@ -3197,22 +3197,22 @@ class TestAddressesXMLSerialization(test.TestCase): }, } output = self.serializer.serialize(fixture, 'index') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(""" - - - - - - - - - - - """.replace(" ", "")) - - self.assertEqual(expected.toxml(), actual.toxml()) + print output + root = etree.XML(output) + xmlutil.validate_schema(root, 'addresses') + addresses_dict = fixture['addresses'] + network_elems = root.findall('{0}network'.format(NS)) + self.assertEqual(len(network_elems), 2) + for i, network_elem in enumerate(network_elems): + network = addresses_dict.items()[i] + self.assertEqual(str(network_elem.get('id')), str(network[0])) + ip_elems = network_elem.findall('{0}ip'.format(NS)) + for z, ip_elem in enumerate(ip_elems): + ip = network[1][z] + self.assertEqual(str(ip_elem.get('version')), + str(ip['version'])) + self.assertEqual(str(ip_elem.get('addr')), + str(ip['addr'])) class TestServerInstanceCreation(test.TestCase): -- cgit From b02a5e4f581590c1bf31dae1c9c2bc1e448a6106 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 25 Aug 2011 16:35:04 -0400 Subject: DRYed up code by moving _to_xml into XMLDictSerializer --- nova/tests/api/openstack/test_common.py | 14 +++++ nova/tests/api/openstack/test_flavors.py | 27 ++++++++++ nova/tests/api/openstack/test_images.py | 45 ++++++++++++++++ nova/tests/api/openstack/test_servers.py | 89 ++++++++++++++++++++++++++++++++ 4 files changed, 175 insertions(+) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_common.py b/nova/tests/api/openstack/test_common.py index 2e5bf08fa..867e9d446 100644 --- a/nova/tests/api/openstack/test_common.py +++ b/nova/tests/api/openstack/test_common.py @@ -320,6 +320,20 @@ class MetadataXMLDeserializationTest(test.TestCase): class MetadataXMLSerializationTest(test.TestCase): + def test_xml_declaration(self): + serializer = common.MetadataXMLSerializer() + fixture = { + 'metadata': { + 'one': 'two', + 'three': 'four', + }, + } + + output = serializer.serialize(fixture, 'index') + print output + has_dec = output.startswith("") + self.assertTrue(has_dec) + def test_index(self): serializer = common.MetadataXMLSerializer() fixture = { diff --git a/nova/tests/api/openstack/test_flavors.py b/nova/tests/api/openstack/test_flavors.py index ea5038b39..a3c5bd107 100644 --- a/nova/tests/api/openstack/test_flavors.py +++ b/nova/tests/api/openstack/test_flavors.py @@ -267,6 +267,33 @@ class FlavorsTest(test.TestCase): class FlavorsXMLSerializationTest(test.TestCase): + def test_xml_declaration(self): + serializer = flavors.FlavorXMLSerializer() + + fixture = { + "flavor": { + "id": "12", + "name": "asdf", + "ram": "256", + "disk": "10", + "links": [ + { + "rel": "self", + "href": "http://localhost/v1.1/fake/flavors/12", + }, + { + "rel": "bookmark", + "href": "http://localhost/fake/flavors/12", + }, + ], + }, + } + + output = serializer.serialize(fixture, 'show') + print output + has_dec = output.startswith("") + self.assertTrue(has_dec) + def test_show(self): serializer = flavors.FlavorXMLSerializer() diff --git a/nova/tests/api/openstack/test_images.py b/nova/tests/api/openstack/test_images.py index 145cf527c..97e940974 100644 --- a/nova/tests/api/openstack/test_images.py +++ b/nova/tests/api/openstack/test_images.py @@ -1138,6 +1138,51 @@ class ImageXMLSerializationTest(test.TestCase): IMAGE_HREF = 'http://localhost/v1.1/fake/images/%s' IMAGE_BOOKMARK = 'http://localhost/fake/images/%s' + def test_xml_declaration(self): + serializer = images.ImageXMLSerializer() + + fixture = { + 'image': { + 'id': 1, + 'name': 'Image1', + 'created': self.TIMESTAMP, + 'updated': self.TIMESTAMP, + 'status': 'ACTIVE', + 'progress': 80, + 'server': { + 'id': '1', + 'links': [ + { + 'href': self.SERVER_HREF, + 'rel': 'self', + }, + { + 'href': self.SERVER_BOOKMARK, + 'rel': 'bookmark', + }, + ], + }, + 'metadata': { + 'key1': 'value1', + }, + 'links': [ + { + 'href': self.IMAGE_HREF % 1, + 'rel': 'self', + }, + { + 'href': self.IMAGE_BOOKMARK % 1, + 'rel': 'bookmark', + }, + ], + }, + } + + output = serializer.serialize(fixture, 'show') + print output + has_dec = output.startswith("") + self.assertTrue(has_dec) + def test_show(self): serializer = images.ImageXMLSerializer() diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 0c816f965..d80846747 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -3163,6 +3163,18 @@ class TestAddressesXMLSerialization(test.TestCase): serializer = nova.api.openstack.ips.IPXMLSerializer() + def test_xml_declaration(self): + fixture = { + 'network_2': [ + {'addr': '192.168.0.1', 'version': 4}, + {'addr': 'fe80::beef', 'version': 6}, + ], + } + output = self.serializer.serialize(fixture, 'show') + print output + has_dec = output.startswith("") + self.assertTrue(has_dec) + def test_show(self): fixture = { 'network_2': [ @@ -3918,6 +3930,83 @@ class ServerXMLSerializationTest(test.TestCase): self.maxDiff = None test.TestCase.setUp(self) + def test_xml_declaration(self): + serializer = servers.ServerXMLSerializer() + + fixture = { + "server": { + "id": 1, + "uuid": FAKE_UUID, + 'created': self.TIMESTAMP, + 'updated': self.TIMESTAMP, + "progress": 0, + "name": "test_server", + "status": "BUILD", + "hostId": 'e4d909c290d0fb1ca068ffaddf22cbd0', + "accessIPv4": "1.2.3.4", + "accessIPv6": "fead::1234", + "image": { + "id": "5", + "links": [ + { + "rel": "bookmark", + "href": self.IMAGE_BOOKMARK, + }, + ], + }, + "flavor": { + "id": "1", + "links": [ + { + "rel": "bookmark", + "href": self.FLAVOR_BOOKMARK, + }, + ], + }, + "addresses": { + "network_one": [ + { + "version": 4, + "addr": "67.23.10.138", + }, + { + "version": 6, + "addr": "::babe:67.23.10.138", + }, + ], + "network_two": [ + { + "version": 4, + "addr": "67.23.10.139", + }, + { + "version": 6, + "addr": "::babe:67.23.10.139", + }, + ], + }, + "metadata": { + "Open": "Stack", + "Number": "1", + }, + 'links': [ + { + 'href': self.SERVER_HREF, + 'rel': 'self', + }, + { + 'href': self.SERVER_BOOKMARK, + 'rel': 'bookmark', + }, + ], + } + } + + output = serializer.serialize(fixture, 'show') + print output + has_dec = output.startswith("") + self.assertTrue(has_dec) + def test_show(self): serializer = servers.ServerXMLSerializer() -- cgit From 86029908254850e9d04fcc2399eef54e7af58193 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 25 Aug 2011 16:56:21 -0400 Subject: updated tests --- nova/tests/api/openstack/test_servers.py | 46 +++----------------------------- nova/tests/integrated/test_xml.py | 7 ++--- 2 files changed, 8 insertions(+), 45 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index d80846747..87ae19f56 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -428,48 +428,10 @@ class ServersTest(test.TestCase): req = webob.Request.blank('/v1.1/fake/servers/1') req.headers['Accept'] = 'application/xml' res = req.get_response(fakes.wsgi_app()) - actual = minidom.parseString(res.body.replace(' ', '')) - expected_uuid = FAKE_UUID - expected_updated = "2010-11-11T11:00:00Z" - expected_created = "2010-10-10T12:00:00Z" - expected = minidom.parseString(""" - - - - - - - - - - - - 1 - - - - - - - - - - - - """.replace(" ", "") % (locals())) - - self.assertEqual(expected.toxml(), actual.toxml()) + output = res.body + print output + root = etree.XML(output) + xmlutil.validate_schema(root, 'server') def test_get_server_with_active_status_by_id_v1_1(self): image_bookmark = "http://localhost/fake/images/10" diff --git a/nova/tests/integrated/test_xml.py b/nova/tests/integrated/test_xml.py index 74baaacc2..6b4f4c0ec 100644 --- a/nova/tests/integrated/test_xml.py +++ b/nova/tests/integrated/test_xml.py @@ -34,8 +34,8 @@ class XmlTests(integrated_helpers._IntegratedTestBase): response = self.api.api_request('/limits', headers=headers) data = response.read() LOG.debug("data: %s" % data) - - prefix = ' Date: Thu, 25 Aug 2011 17:10:35 -0400 Subject: Fixed integrated.test_xml to be more robust --- nova/tests/integrated/test_xml.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/integrated/test_xml.py b/nova/tests/integrated/test_xml.py index 6b4f4c0ec..cf013da1d 100644 --- a/nova/tests/integrated/test_xml.py +++ b/nova/tests/integrated/test_xml.py @@ -15,6 +15,8 @@ # License for the specific language governing permissions and limitations # under the License. +from lxml import etree + from nova.log import logging from nova.tests.integrated import integrated_helpers from nova.api.openstack import common @@ -34,9 +36,8 @@ class XmlTests(integrated_helpers._IntegratedTestBase): response = self.api.api_request('/limits', headers=headers) data = response.read() LOG.debug("data: %s" % data) - declaration = "" - prefix = '%s Date: Thu, 25 Aug 2011 18:01:35 -0400 Subject: Updated limits serialization tests to use etree and added limits schema --- nova/tests/api/openstack/test_limits.py | 56 ++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 26 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_limits.py b/nova/tests/api/openstack/test_limits.py index 801b06230..a3bcecc3a 100644 --- a/nova/tests/api/openstack/test_limits.py +++ b/nova/tests/api/openstack/test_limits.py @@ -19,6 +19,7 @@ Tests dealing with HTTP rate-limiting. import httplib import json +from lxml import etree import StringIO import stubout import time @@ -29,6 +30,7 @@ from xml.dom import minidom import nova.context from nova.api.openstack import limits from nova.api.openstack import views +from nova.api.openstack import xmlutil from nova import test @@ -39,6 +41,8 @@ TEST_LIMITS = [ limits.Limit("PUT", "*", "", 10, limits.PER_MINUTE), limits.Limit("PUT", "/servers", "^/servers", 5, limits.PER_MINUTE), ] +NS = "{http://docs.openstack.org/compute/api/v1.1}" +ATOMNS = "{http://www.w3.org/2005/Atom}" class BaseLimitTestSuite(unittest.TestCase): @@ -1006,32 +1010,32 @@ class LimitsXMLSerializationTest(test.TestCase): "maxPersonalitySize": 10240}}} output = serializer.serialize(fixture, 'index') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(""" - - - - - - - - - - - - - - - - - """.replace(" ", "")) - - self.assertEqual(expected.toxml(), actual.toxml()) + print output + root = etree.XML(output) + xmlutil.validate_schema(root, 'limits') + + #verify absolute limits + absolute = root.find('{0}absolute'.format(NS)) + absolutes = absolute.findall('limit'.format(NS)) + for limit in absolutes: + name = limit.get('name') + value = limit.get('value') + self.assertEqual(value, str(fixture['limits']['absolute'][name])) + + #verify rate limits + rate_root = root.find('{0}rates'.format(NS)) + rates = rate_root.findall('{0}rate'.format(NS)) + for i in range(len(rates)): + rate = rates[i] + for key in ['uri', 'regex']: + self.assertEqual(rate.get(key), str(fixture['limits']['rate'][i][key])) + rate_limits = rate.findall('{0}limit'.format(NS)) + for z in range(len(rate_limits)): + limit = rate_limits[z] + for key in ['verb', 'value', 'remaining', 'unit', + 'next-available']: + self.assertEqual(limit.get(key), + str(fixture['limits']['rate'][i]['limit'][z][key])) def test_index_no_limits(self): serializer = limits.LimitsXMLSerializer() -- cgit From bebc02efbf4f049efeb4e1f72a21a8fdc825903a Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 25 Aug 2011 18:08:46 -0400 Subject: pep8 --- nova/tests/api/openstack/test_limits.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_limits.py b/nova/tests/api/openstack/test_limits.py index a3bcecc3a..888f62697 100644 --- a/nova/tests/api/openstack/test_limits.py +++ b/nova/tests/api/openstack/test_limits.py @@ -1028,14 +1028,15 @@ class LimitsXMLSerializationTest(test.TestCase): for i in range(len(rates)): rate = rates[i] for key in ['uri', 'regex']: - self.assertEqual(rate.get(key), str(fixture['limits']['rate'][i][key])) + self.assertEqual(rate.get(key), + str(fixture['limits']['rate'][i][key])) rate_limits = rate.findall('{0}limit'.format(NS)) for z in range(len(rate_limits)): limit = rate_limits[z] for key in ['verb', 'value', 'remaining', 'unit', 'next-available']: self.assertEqual(limit.get(key), - str(fixture['limits']['rate'][i]['limit'][z][key])) + str(fixture['limits']['rate'][i]['limit'][z][key])) def test_index_no_limits(self): serializer = limits.LimitsXMLSerializer() -- cgit From bcdec7da59ade484d370fb4a605e4f6926038252 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 25 Aug 2011 18:10:43 -0400 Subject: updated additional limits test --- nova/tests/api/openstack/test_limits.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_limits.py b/nova/tests/api/openstack/test_limits.py index 888f62697..250d97101 100644 --- a/nova/tests/api/openstack/test_limits.py +++ b/nova/tests/api/openstack/test_limits.py @@ -1046,13 +1046,16 @@ class LimitsXMLSerializationTest(test.TestCase): "absolute": {}}} output = serializer.serialize(fixture, 'index') - actual = minidom.parseString(output.replace(" ", "")) + print output + root = etree.XML(output) + xmlutil.validate_schema(root, 'limits') - expected = minidom.parseString(""" - - - - - """.replace(" ", "")) + #verify absolute limits + absolute = root.find('{0}absolute'.format(NS)) + absolutes = absolute.findall('limit'.format(NS)) + self.assertEqual(len(absolutes), 0) - self.assertEqual(expected.toxml(), actual.toxml()) + #verify rate limits + rate_root = root.find('{0}rates'.format(NS)) + rates = rate_root.findall('{0}rate'.format(NS)) + self.assertEqual(len(rates), 0) -- cgit From e4966cc21ca34380be98a9f24c76404ca43f663f Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 25 Aug 2011 18:31:41 -0400 Subject: updated LimitsXMLSerializer to use etree and supply the xml declaration --- nova/tests/api/openstack/test_limits.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_limits.py b/nova/tests/api/openstack/test_limits.py index 250d97101..f71d9c454 100644 --- a/nova/tests/api/openstack/test_limits.py +++ b/nova/tests/api/openstack/test_limits.py @@ -984,6 +984,18 @@ class LimitsXMLSerializationTest(test.TestCase): def tearDown(self): pass + def test_xml_declaration(self): + serializer = limits.LimitsXMLSerializer() + + fixture = {"limits": { + "rate": [], + "absolute": {}}} + + output = serializer.serialize(fixture, 'index') + print output + has_dec = output.startswith("") + self.assertTrue(has_dec) + def test_index(self): serializer = limits.LimitsXMLSerializer() fixture = {"limits": { -- cgit From e39ec75169ff3b7ac29212ca315ad213997a8cbc Mon Sep 17 00:00:00 2001 From: Naveed Massjouni Date: Sat, 27 Aug 2011 04:32:20 -0400 Subject: Updated VersionsXMLSerializer and corresponding tests to use lxml. --- nova/tests/api/openstack/test_versions.py | 176 ++++++++++++------------------ 1 file changed, 72 insertions(+), 104 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_versions.py b/nova/tests/api/openstack/test_versions.py index 1269f13c9..3b4396b1a 100644 --- a/nova/tests/api/openstack/test_versions.py +++ b/nova/tests/api/openstack/test_versions.py @@ -18,8 +18,7 @@ import json import stubout import webob -import xml.etree.ElementTree - +from lxml import etree from nova import context from nova import test @@ -28,6 +27,10 @@ from nova.api.openstack import versions from nova.api.openstack import views from nova.api.openstack import wsgi +NS = { + 'atom': 'http://www.w3.org/2005/Atom', + 'ns': 'http://docs.openstack.org/compute/api/v1.1' +} VERSIONS = { "v1.0": { "id": "v1.0", @@ -113,23 +116,23 @@ class VersionsTest(test.TestCase): versions = json.loads(res.body)["versions"] expected = [ { - "id": "v1.1", - "status": "CURRENT", + "id": "v1.0", + "status": "DEPRECATED", "updated": "2011-01-21T11:33:21Z", "links": [ { "rel": "self", - "href": "http://localhost/v1.1/", + "href": "http://localhost/v1.0/", }], }, { - "id": "v1.0", - "status": "DEPRECATED", + "id": "v1.1", + "status": "CURRENT", "updated": "2011-01-21T11:33:21Z", "links": [ { "rel": "self", - "href": "http://localhost/v1.0/", + "href": "http://localhost/v1.1/", }], }, ] @@ -233,48 +236,19 @@ class VersionsTest(test.TestCase): res = req.get_response(fakes.wsgi_app()) self.assertEqual(res.status_int, 200) self.assertEqual(res.content_type, "application/xml") - root = xml.etree.ElementTree.XML(res.body) - self.assertEqual(root.tag.split('}')[1], "version") - self.assertEqual(root.tag.split('}')[0].strip('{'), wsgi.XMLNS_V11) - children = list(root) - media_types = children[0] - media_type_nodes = list(media_types) - links = (children[1], children[2], children[3]) - - self.assertEqual(media_types.tag.split('}')[1], 'media-types') - for media_node in media_type_nodes: - self.assertEqual(media_node.tag.split('}')[1], 'media-type') - - expected = """ - - - - - - - - - - - - - """.replace(" ", "").replace("\n", "") % wsgi.XMLNS_V11 - - actual = res.body.replace(" ", "").replace("\n", "") - self.assertEqual(expected, actual) + version = etree.XML(res.body) + expected = VERSIONS['v1.0'] + self.assertTrue(version.xpath('/ns:version', namespaces=NS)) + media_types = version.xpath('ns:media-types/ns:media-type', + namespaces=NS) + self._compare_media_types(media_types, expected['media-types']) + for key in ['id', 'status', 'updated']: + self.assertEqual(version.get(key), expected[key]) + links = version.xpath('atom:link', namespaces=NS) + self._compare_links(links, + [{'rel': 'self', 'href': 'http://localhost/v1.0/'}] + + expected['links']) def test_get_version_1_1_detail_xml(self): req = webob.Request.blank('/v1.1/') @@ -282,35 +256,19 @@ class VersionsTest(test.TestCase): res = req.get_response(fakes.wsgi_app()) self.assertEqual(res.status_int, 200) self.assertEqual(res.content_type, "application/xml") - expected = """ - - - - - - - - - - - - - """.replace(" ", "").replace("\n", "") % wsgi.XMLNS_V11 - actual = res.body.replace(" ", "").replace("\n", "") - self.assertEqual(expected, actual) + version = etree.XML(res.body) + expected = VERSIONS['v1.1'] + self.assertTrue(version.xpath('/ns:version', namespaces=NS)) + media_types = version.xpath('ns:media-types/ns:media-type', + namespaces=NS) + self._compare_media_types(media_types, expected['media-types']) + for key in ['id', 'status', 'updated']: + self.assertEqual(version.get(key), expected[key]) + links = version.xpath('atom:link', namespaces=NS) + self._compare_links(links, + [{'rel': 'self', 'href': 'http://localhost/v1.1/'}] + + expected['links']) def test_get_version_list_xml(self): req = webob.Request.blank('/') @@ -319,21 +277,19 @@ class VersionsTest(test.TestCase): self.assertEqual(res.status_int, 200) self.assertEqual(res.content_type, "application/xml") - expected = """ - - - - - - - - """.replace(" ", "").replace("\n", "") % (wsgi.XMLNS_V11, - wsgi.XMLNS_ATOM) - - actual = res.body.replace(" ", "").replace("\n", "") + root = etree.XML(res.body) + self.assertTrue(root.xpath('/ns:versions', namespaces=NS)) + versions = root.xpath('ns:version', namespaces=NS) + self.assertEqual(len(versions), 2) - self.assertEqual(expected, actual) + for (i, v) in ((0, 'v1.0'), (1, 'v1.1')): + version = versions[i] + expected = VERSIONS[v] + for key in ['id', 'status', 'updated']: + self.assertEqual(version.get(key), expected[key]) + (link,) = version.xpath('atom:link', namespaces=NS) + self._compare_links(link, + [{'rel': 'self', 'href': 'http://localhost/%s/' % v}]) def test_get_version_1_0_detail_atom(self): req = webob.Request.blank('/v1.0/') @@ -427,21 +383,21 @@ class VersionsTest(test.TestCase): - http://localhost/v1.1/ - Version v1.1 + http://localhost/v1.0/ + Version v1.0 2011-01-21T11:33:21Z - + - Version v1.1 CURRENT (2011-01-21T11:33:21Z) + Version v1.0 DEPRECATED (2011-01-21T11:33:21Z) - http://localhost/v1.0/ - Version v1.0 + http://localhost/v1.1/ + Version v1.1 2011-01-21T11:33:21Z - + - Version v1.0 DEPRECATED (2011-01-21T11:33:21Z) + Version v1.1 CURRENT (2011-01-21T11:33:21Z) @@ -598,6 +554,18 @@ class VersionsTest(test.TestCase): self.assertDictMatch(expected, json.loads(res.body)) + def _compare_media_types(self, actual, expected): + for elem, data in zip(actual, expected): + self.assertEqual(elem.get('base'), data['base']) + self.assertEqual(elem.get('type'), data['type']) + + def _compare_links(self, actual, expected): + for elem, data in zip(actual, expected): + self.assertEqual(elem.get('rel'), data['rel']) + self.assertEqual(elem.get('href'), data['href']) + if 'type' in data: + self.assertEqual(elem.get('type'), data['type']) + class VersionsViewBuilderTests(test.TestCase): def test_view_builder(self): @@ -665,7 +633,7 @@ class VersionsSerializerTests(test.TestCase): serializer = versions.VersionsXMLSerializer() response = serializer.index(versions_data) - root = xml.etree.ElementTree.XML(response) + root = etree.XML(response) self.assertEqual(root.tag.split('}')[1], "versions") self.assertEqual(root.tag.split('}')[0].strip('{'), wsgi.XMLNS_V11) version = list(root)[0] @@ -703,7 +671,7 @@ class VersionsSerializerTests(test.TestCase): serializer = versions.VersionsXMLSerializer() response = serializer.multi(versions_data) - root = xml.etree.ElementTree.XML(response) + root = etree.XML(response) self.assertEqual(root.tag.split('}')[1], "choices") self.assertEqual(root.tag.split('}')[0].strip('{'), wsgi.XMLNS_V11) version = list(root)[0] @@ -770,7 +738,7 @@ class VersionsSerializerTests(test.TestCase): serializer = versions.VersionsXMLSerializer() response = serializer.show(version_data) - root = xml.etree.ElementTree.XML(response) + root = etree.XML(response) self.assertEqual(root.tag.split('}')[1], "version") self.assertEqual(root.tag.split('}')[0].strip('{'), wsgi.XMLNS_V11) @@ -812,7 +780,7 @@ class VersionsSerializerTests(test.TestCase): serializer = versions.VersionsAtomSerializer() response = serializer.index(versions_data) - root = xml.etree.ElementTree.XML(response) + root = etree.XML(response) self.assertEqual(root.tag.split('}')[1], "feed") self.assertEqual(root.tag.split('}')[0].strip('{'), "http://www.w3.org/2005/Atom") @@ -905,7 +873,7 @@ class VersionsSerializerTests(test.TestCase): serializer = versions.VersionsAtomSerializer() response = serializer.show(versions_data) - root = xml.etree.ElementTree.XML(response) + root = etree.XML(response) self.assertEqual(root.tag.split('}')[1], "feed") self.assertEqual(root.tag.split('}')[0].strip('{'), "http://www.w3.org/2005/Atom") -- cgit From 9e3fd76a2f7d55ef111631e6ffac5575a6dd4817 Mon Sep 17 00:00:00 2001 From: Naveed Massjouni Date: Wed, 31 Aug 2011 02:35:01 -0400 Subject: Use feedparser to parse the generated atom feeds in the tests for the versions resource. --- nova/tests/api/openstack/test_versions.py | 374 +++++++++++++----------------- 1 file changed, 167 insertions(+), 207 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_versions.py b/nova/tests/api/openstack/test_versions.py index 3b4396b1a..57a81738c 100644 --- a/nova/tests/api/openstack/test_versions.py +++ b/nova/tests/api/openstack/test_versions.py @@ -15,6 +15,7 @@ # License for the specific language governing permissions and limitations # under the License. +import feedparser import json import stubout import webob @@ -297,36 +298,43 @@ class VersionsTest(test.TestCase): res = req.get_response(fakes.wsgi_app()) self.assertEqual(res.status_int, 200) self.assertEqual("application/atom+xml", res.content_type) - expected = """ - - About This Version - 2011-01-21T11:33:21Z - http://localhost/v1.0/ - - Rackspace - http://www.rackspace.com/ - - - - http://localhost/v1.0/ - Version v1.0 - 2011-01-21T11:33:21Z - - - - - Version v1.0 DEPRECATED (2011-01-21T11:33:21Z) - - - """.replace(" ", "").replace("\n", "") - - actual = res.body.replace(" ", "").replace("\n", "") - self.assertEqual(expected, actual) + + f = feedparser.parse(res.body) + self.assertEqual(f.feed.title, 'About This Version') + self.assertEqual(f.feed.updated, '2011-01-21T11:33:21Z') + self.assertEqual(f.feed.id, 'http://localhost/v1.0/') + self.assertEqual(f.feed.author, 'Rackspace') + self.assertEqual(f.feed.author_detail.href, 'http://www.rackspace.com/') + self.assertEqual(f.feed.links, [{'href': 'http://localhost/v1.0/', + 'type': 'application/atom+xml', + 'rel': 'self'}]) + + self.assertEqual(len(f.entries), 1) + entry = f.entries[0] + self.assertEqual(entry.id, 'http://localhost/v1.0/') + self.assertEqual(entry.title, 'Version v1.0') + self.assertEqual(entry.updated, '2011-01-21T11:33:21Z') + self.assertEqual(len(entry.content), 1) + self.assertEqual(entry.content[0].value, + 'Version v1.0 DEPRECATED (2011-01-21T11:33:21Z)') + self.assertEqual(entry.links, [ + { + 'href': 'http://localhost/v1.0/', + 'type': 'application/atom+xml', + 'rel': 'self' + }, + { + 'href': 'http://docs.rackspacecloud.com/servers/api/v1.0/'\ + 'cs-devguide-20110125.pdf', + 'type': 'application/pdf', + 'rel': 'describedby' + }, + { + 'href': 'http://docs.rackspacecloud.com/servers/api/v1.0/'\ + 'application.wadl', + 'type': 'application/vnd.sun.wadl+xml', + 'rel': 'describedby' + }]) def test_get_version_1_1_detail_atom(self): req = webob.Request.blank('/v1.1/') @@ -334,36 +342,43 @@ class VersionsTest(test.TestCase): res = req.get_response(fakes.wsgi_app()) self.assertEqual(res.status_int, 200) self.assertEqual("application/atom+xml", res.content_type) - expected = """ - - About This Version - 2011-01-21T11:33:21Z - http://localhost/v1.1/ - - Rackspace - http://www.rackspace.com/ - - - - http://localhost/v1.1/ - Version v1.1 - 2011-01-21T11:33:21Z - - - - - Version v1.1 CURRENT (2011-01-21T11:33:21Z) - - - """.replace(" ", "").replace("\n", "") - - actual = res.body.replace(" ", "").replace("\n", "") - self.assertEqual(expected, actual) + + f = feedparser.parse(res.body) + self.assertEqual(f.feed.title, 'About This Version') + self.assertEqual(f.feed.updated, '2011-01-21T11:33:21Z') + self.assertEqual(f.feed.id, 'http://localhost/v1.1/') + self.assertEqual(f.feed.author, 'Rackspace') + self.assertEqual(f.feed.author_detail.href, 'http://www.rackspace.com/') + self.assertEqual(f.feed.links, [{'href': 'http://localhost/v1.1/', + 'type': 'application/atom+xml', + 'rel': 'self'}]) + + self.assertEqual(len(f.entries), 1) + entry = f.entries[0] + self.assertEqual(entry.id, 'http://localhost/v1.1/') + self.assertEqual(entry.title, 'Version v1.1') + self.assertEqual(entry.updated, '2011-01-21T11:33:21Z') + self.assertEqual(len(entry.content), 1) + self.assertEqual(entry.content[0].value, + 'Version v1.1 CURRENT (2011-01-21T11:33:21Z)') + self.assertEqual(entry.links, [ + { + 'href': 'http://localhost/v1.1/', + 'type': 'application/atom+xml', + 'rel': 'self' + }, + { + 'href': 'http://docs.rackspacecloud.com/servers/api/v1.1/'\ + 'cs-devguide-20110125.pdf', + 'type': 'application/pdf', + 'rel': 'describedby' + }, + { + 'href': 'http://docs.rackspacecloud.com/servers/api/v1.1/'\ + 'application.wadl', + 'type': 'application/vnd.sun.wadl+xml', + 'rel': 'describedby' + }]) def test_get_version_list_atom(self): req = webob.Request.blank('/') @@ -372,40 +387,39 @@ class VersionsTest(test.TestCase): self.assertEqual(res.status_int, 200) self.assertEqual(res.content_type, "application/atom+xml") - expected = """ - - Available API Versions - 2011-01-21T11:33:21Z - http://localhost/ - - Rackspace - http://www.rackspace.com/ - - - - http://localhost/v1.0/ - Version v1.0 - 2011-01-21T11:33:21Z - - - Version v1.0 DEPRECATED (2011-01-21T11:33:21Z) - - - - http://localhost/v1.1/ - Version v1.1 - 2011-01-21T11:33:21Z - - - Version v1.1 CURRENT (2011-01-21T11:33:21Z) - - - - """.replace(" ", "").replace("\n", "") - - actual = res.body.replace(" ", "").replace("\n", "") - - self.assertEqual(expected, actual) + f = feedparser.parse(res.body) + self.assertEqual(f.feed.title, 'Available API Versions') + self.assertEqual(f.feed.updated, '2011-01-21T11:33:21Z') + self.assertEqual(f.feed.id, 'http://localhost/') + self.assertEqual(f.feed.author, 'Rackspace') + self.assertEqual(f.feed.author_detail.href, 'http://www.rackspace.com/') + self.assertEqual(f.feed.links, [{'href': 'http://localhost/', + 'type': 'application/atom+xml', + 'rel': 'self'}]) + + self.assertEqual(len(f.entries), 2) + entry = f.entries[0] + self.assertEqual(entry.id, 'http://localhost/v1.0/') + self.assertEqual(entry.title, 'Version v1.0') + self.assertEqual(entry.updated, '2011-01-21T11:33:21Z') + self.assertEqual(len(entry.content), 1) + self.assertEqual(entry.content[0].value, + 'Version v1.0 DEPRECATED (2011-01-21T11:33:21Z)') + self.assertEqual(entry.links, [{ + 'href': 'http://localhost/v1.0/', + 'type': 'application/atom+xml', + 'rel': 'self'}]) + entry = f.entries[1] + self.assertEqual(entry.id, 'http://localhost/v1.1/') + self.assertEqual(entry.title, 'Version v1.1') + self.assertEqual(entry.updated, '2011-01-21T11:33:21Z') + self.assertEqual(len(entry.content), 1) + self.assertEqual(entry.content[0].value, + 'Version v1.1 CURRENT (2011-01-21T11:33:21Z)') + self.assertEqual(entry.links, [{ + 'href': 'http://localhost/v1.1/', + 'type': 'application/atom+xml', + 'rel': 'self'}]) def test_multi_choice_image(self): req = webob.Request.blank('/images/1') @@ -779,59 +793,28 @@ class VersionsSerializerTests(test.TestCase): serializer = versions.VersionsAtomSerializer() response = serializer.index(versions_data) - - root = etree.XML(response) - self.assertEqual(root.tag.split('}')[1], "feed") - self.assertEqual(root.tag.split('}')[0].strip('{'), - "http://www.w3.org/2005/Atom") - - children = list(root) - title = children[0] - updated = children[1] - id = children[2] - author = children[3] - link = children[4] - entry = children[5] - - self.assertEqual(title.tag.split('}')[1], 'title') - self.assertEqual(title.text, 'Available API Versions') - self.assertEqual(updated.tag.split('}')[1], 'updated') - self.assertEqual(updated.text, '2011-07-20T11:40:00Z') - self.assertEqual(id.tag.split('}')[1], 'id') - self.assertEqual(id.text, 'http://test/') - - self.assertEqual(author.tag.split('}')[1], 'author') - author_name = list(author)[0] - author_uri = list(author)[1] - self.assertEqual(author_name.tag.split('}')[1], 'name') - self.assertEqual(author_name.text, 'Rackspace') - self.assertEqual(author_uri.tag.split('}')[1], 'uri') - self.assertEqual(author_uri.text, 'http://www.rackspace.com/') - - self.assertEqual(link.get('href'), 'http://test/') - self.assertEqual(link.get('rel'), 'self') - - self.assertEqual(entry.tag.split('}')[1], 'entry') - entry_children = list(entry) - entry_id = entry_children[0] - entry_title = entry_children[1] - entry_updated = entry_children[2] - entry_link = entry_children[3] - entry_content = entry_children[4] - self.assertEqual(entry_id.tag.split('}')[1], "id") - self.assertEqual(entry_id.text, "http://test/2.9.8") - self.assertEqual(entry_title.tag.split('}')[1], "title") - self.assertEqual(entry_title.get('type'), "text") - self.assertEqual(entry_title.text, "Version 2.9.8") - self.assertEqual(entry_updated.tag.split('}')[1], "updated") - self.assertEqual(entry_updated.text, "2011-07-20T11:40:00Z") - self.assertEqual(entry_link.tag.split('}')[1], "link") - self.assertEqual(entry_link.get('href'), "http://test/2.9.8") - self.assertEqual(entry_link.get('rel'), "self") - self.assertEqual(entry_content.tag.split('}')[1], "content") - self.assertEqual(entry_content.get('type'), "text") - self.assertEqual(entry_content.text, - "Version 2.9.8 CURRENT (2011-07-20T11:40:00Z)") + f = feedparser.parse(response) + + self.assertEqual(f.feed.title, 'Available API Versions') + self.assertEqual(f.feed.updated, '2011-07-20T11:40:00Z') + self.assertEqual(f.feed.id, 'http://test/') + self.assertEqual(f.feed.author, 'Rackspace') + self.assertEqual(f.feed.author_detail.href, 'http://www.rackspace.com/') + self.assertEqual(f.feed.links, [{'href': 'http://test/', + 'type': 'application/atom+xml', + 'rel': 'self'}]) + self.assertEqual(len(f.entries), 1) + entry = f.entries[0] + self.assertEqual(entry.id, 'http://test/2.9.8') + self.assertEqual(entry.title, 'Version 2.9.8') + self.assertEqual(entry.updated, '2011-07-20T11:40:00Z') + self.assertEqual(len(entry.content), 1) + self.assertEqual(entry.content[0].value, + 'Version 2.9.8 CURRENT (2011-07-20T11:40:00Z)') + self.assertEqual(entry.links, [{ + 'href': 'http://test/2.9.8', + 'type': 'application/atom+xml', + 'rel': 'self'}]) def test_version_detail_atom_serializer(self): versions_data = { @@ -872,63 +855,40 @@ class VersionsSerializerTests(test.TestCase): serializer = versions.VersionsAtomSerializer() response = serializer.show(versions_data) - - root = etree.XML(response) - self.assertEqual(root.tag.split('}')[1], "feed") - self.assertEqual(root.tag.split('}')[0].strip('{'), - "http://www.w3.org/2005/Atom") - - children = list(root) - title = children[0] - updated = children[1] - id = children[2] - author = children[3] - link = children[4] - entry = children[5] - - self.assertEqual(root.tag.split('}')[1], 'feed') - self.assertEqual(title.tag.split('}')[1], 'title') - self.assertEqual(title.text, 'About This Version') - self.assertEqual(updated.tag.split('}')[1], 'updated') - self.assertEqual(updated.text, '2011-01-21T11:33:21Z') - self.assertEqual(id.tag.split('}')[1], 'id') - self.assertEqual(id.text, 'http://localhost/v1.1/') - - self.assertEqual(author.tag.split('}')[1], 'author') - author_name = list(author)[0] - author_uri = list(author)[1] - self.assertEqual(author_name.tag.split('}')[1], 'name') - self.assertEqual(author_name.text, 'Rackspace') - self.assertEqual(author_uri.tag.split('}')[1], 'uri') - self.assertEqual(author_uri.text, 'http://www.rackspace.com/') - - self.assertEqual(link.get('href'), - 'http://localhost/v1.1/') - self.assertEqual(link.get('rel'), 'self') - - self.assertEqual(entry.tag.split('}')[1], 'entry') - entry_children = list(entry) - entry_id = entry_children[0] - entry_title = entry_children[1] - entry_updated = entry_children[2] - entry_links = (entry_children[3], entry_children[4], entry_children[5]) - entry_content = entry_children[6] - - self.assertEqual(entry_id.tag.split('}')[1], "id") - self.assertEqual(entry_id.text, - "http://localhost/v1.1/") - self.assertEqual(entry_title.tag.split('}')[1], "title") - self.assertEqual(entry_title.get('type'), "text") - self.assertEqual(entry_title.text, "Version v1.1") - self.assertEqual(entry_updated.tag.split('}')[1], "updated") - self.assertEqual(entry_updated.text, "2011-01-21T11:33:21Z") - - for i, link in enumerate(versions_data["version"]["links"]): - self.assertEqual(entry_links[i].tag.split('}')[1], "link") - for key, val in versions_data["version"]["links"][i].items(): - self.assertEqual(entry_links[i].get(key), val) - - self.assertEqual(entry_content.tag.split('}')[1], "content") - self.assertEqual(entry_content.get('type'), "text") - self.assertEqual(entry_content.text, - "Version v1.1 CURRENT (2011-01-21T11:33:21Z)") + f = feedparser.parse(response) + + self.assertEqual(f.feed.title, 'About This Version') + self.assertEqual(f.feed.updated, '2011-01-21T11:33:21Z') + self.assertEqual(f.feed.id, 'http://localhost/v1.1/') + self.assertEqual(f.feed.author, 'Rackspace') + self.assertEqual(f.feed.author_detail.href, 'http://www.rackspace.com/') + self.assertEqual(f.feed.links, [{'href': 'http://localhost/v1.1/', + 'type': 'application/atom+xml', + 'rel': 'self'}]) + self.assertEqual(len(f.entries), 1) + entry = f.entries[0] + self.assertEqual(entry.id, 'http://localhost/v1.1/') + self.assertEqual(entry.title, 'Version v1.1') + self.assertEqual(entry.updated, '2011-01-21T11:33:21Z') + self.assertEqual(len(entry.content), 1) + self.assertEqual(entry.content[0].value, + 'Version v1.1 CURRENT (2011-01-21T11:33:21Z)') + self.assertEqual(entry.links, [ + { + 'rel': 'self', + 'type': 'application/atom+xml', + 'href': 'http://localhost/v1.1/', + }, + { + 'rel': 'describedby', + 'type': 'application/pdf', + 'href': 'http://docs.rackspacecloud.com/' + 'servers/api/v1.1/cs-devguide-20110125.pdf', + }, + { + 'rel': 'describedby', + 'type': 'application/vnd.sun.wadl+xml', + 'href': 'http://docs.rackspacecloud.com/' + 'servers/api/v1.1/application.wadl', + }, + ]) -- cgit From 13d68b59833f55d69497a0f5ac5ec8904af9ab0a Mon Sep 17 00:00:00 2001 From: Naveed Massjouni Date: Wed, 31 Aug 2011 03:40:42 -0400 Subject: Code cleanup. --- nova/tests/api/openstack/test_versions.py | 94 +++++++++++++++---------------- 1 file changed, 46 insertions(+), 48 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_versions.py b/nova/tests/api/openstack/test_versions.py index 57a81738c..129d1e69d 100644 --- a/nova/tests/api/openstack/test_versions.py +++ b/nova/tests/api/openstack/test_versions.py @@ -243,13 +243,14 @@ class VersionsTest(test.TestCase): self.assertTrue(version.xpath('/ns:version', namespaces=NS)) media_types = version.xpath('ns:media-types/ns:media-type', namespaces=NS) - self._compare_media_types(media_types, expected['media-types']) + self.assertTrue(_compare_media_types(media_types, + expected['media-types'])) for key in ['id', 'status', 'updated']: self.assertEqual(version.get(key), expected[key]) links = version.xpath('atom:link', namespaces=NS) - self._compare_links(links, + self.assertTrue(_compare_links(links, [{'rel': 'self', 'href': 'http://localhost/v1.0/'}] - + expected['links']) + + expected['links'])) def test_get_version_1_1_detail_xml(self): req = webob.Request.blank('/v1.1/') @@ -263,13 +264,14 @@ class VersionsTest(test.TestCase): self.assertTrue(version.xpath('/ns:version', namespaces=NS)) media_types = version.xpath('ns:media-types/ns:media-type', namespaces=NS) - self._compare_media_types(media_types, expected['media-types']) + self.assertTrue(_compare_media_types(media_types, + expected['media-types'])) for key in ['id', 'status', 'updated']: self.assertEqual(version.get(key), expected[key]) links = version.xpath('atom:link', namespaces=NS) - self._compare_links(links, + self.assertTrue(_compare_links(links, [{'rel': 'self', 'href': 'http://localhost/v1.1/'}] - + expected['links']) + + expected['links'])) def test_get_version_list_xml(self): req = webob.Request.blank('/') @@ -289,8 +291,8 @@ class VersionsTest(test.TestCase): for key in ['id', 'status', 'updated']: self.assertEqual(version.get(key), expected[key]) (link,) = version.xpath('atom:link', namespaces=NS) - self._compare_links(link, - [{'rel': 'self', 'href': 'http://localhost/%s/' % v}]) + self.assertTrue(_compare_links(link, + [{'rel': 'self', 'href': 'http://localhost/%s/' % v}])) def test_get_version_1_0_detail_atom(self): req = webob.Request.blank('/v1.0/') @@ -568,18 +570,6 @@ class VersionsTest(test.TestCase): self.assertDictMatch(expected, json.loads(res.body)) - def _compare_media_types(self, actual, expected): - for elem, data in zip(actual, expected): - self.assertEqual(elem.get('base'), data['base']) - self.assertEqual(elem.get('type'), data['type']) - - def _compare_links(self, actual, expected): - for elem, data in zip(actual, expected): - self.assertEqual(elem.get('rel'), data['rel']) - self.assertEqual(elem.get('href'), data['href']) - if 'type' in data: - self.assertEqual(elem.get('type'), data['type']) - class VersionsViewBuilderTests(test.TestCase): def test_view_builder(self): @@ -648,21 +638,19 @@ class VersionsSerializerTests(test.TestCase): response = serializer.index(versions_data) root = etree.XML(response) - self.assertEqual(root.tag.split('}')[1], "versions") - self.assertEqual(root.tag.split('}')[0].strip('{'), wsgi.XMLNS_V11) - version = list(root)[0] - self.assertEqual(version.tag.split('}')[1], "version") - self.assertEqual(version.get('id'), - versions_data['versions'][0]['id']) + self.assertTrue(root.xpath('/ns:versions', namespaces=NS)) + version_elems = root.xpath('ns:version', namespaces=NS) + self.assertEqual(len(version_elems), 1) + version = version_elems[0] + self.assertEqual(version.get('id'), versions_data['versions'][0]['id']) self.assertEqual(version.get('status'), versions_data['versions'][0]['status']) - link = list(version)[0] - - self.assertEqual(link.tag.split('}')[1], "link") - self.assertEqual(link.tag.split('}')[0].strip('{'), wsgi.XMLNS_ATOM) - for key, val in versions_data['versions'][0]['links'][0].items(): - self.assertEqual(link.get(key), val) + (link,) = version.xpath('atom:link', namespaces=NS) + self.assertTrue(_compare_links(link, [{ + 'rel': 'self', + 'href': 'http://test/2.7.1', + 'type': 'application/atom+xml'}])) def test_versions_multi_xml_serializer(self): versions_data = { @@ -686,10 +674,8 @@ class VersionsSerializerTests(test.TestCase): response = serializer.multi(versions_data) root = etree.XML(response) - self.assertEqual(root.tag.split('}')[1], "choices") - self.assertEqual(root.tag.split('}')[0].strip('{'), wsgi.XMLNS_V11) - version = list(root)[0] - self.assertEqual(version.tag.split('}')[1], "version") + self.assertTrue(root.xpath('/ns:choices', namespaces=NS)) + (version,) = root.xpath('ns:version', namespaces=NS) self.assertEqual(version.get('id'), versions_data['choices'][0]['id']) self.assertEqual(version.get('status'), versions_data['choices'][0]['status']) @@ -698,19 +684,14 @@ class VersionsSerializerTests(test.TestCase): media_type_nodes = list(media_types) self.assertEqual(media_types.tag.split('}')[1], "media-types") - set_types = versions_data['choices'][0]['media-types'] - for i, type in enumerate(set_types): - node = media_type_nodes[i] - self.assertEqual(node.tag.split('}')[1], "media-type") - for key, val in set_types[i].items(): - self.assertEqual(node.get(key), val) - - link = list(version)[1] + media_types = version.xpath('ns:media-types/ns:media-type', + namespaces=NS) + self.assertTrue(_compare_media_types(media_types, + versions_data['choices'][0]['media-types'])) - self.assertEqual(link.tag.split('}')[1], "link") - self.assertEqual(link.tag.split('}')[0].strip('{'), wsgi.XMLNS_ATOM) - for key, val in versions_data['choices'][0]['links'][0].items(): - self.assertEqual(link.get(key), val) + (link,) = version.xpath('atom:link', namespaces=NS) + self.assertTrue(_compare_links(link, + versions_data['choices'][0]['links'])) def test_version_detail_xml_serializer(self): version_data = { @@ -892,3 +873,20 @@ class VersionsSerializerTests(test.TestCase): 'servers/api/v1.1/application.wadl', }, ]) + + +def _compare_links(actual, expected): + for elem, data in zip(actual, expected): + for key in ('rel', 'href', 'type'): + if elem.get(key) != data.get(key): + return False + return True + + +def _compare_media_types(actual, expected): + for elem, data in zip(actual, expected): + for key in ('base', 'type'): + if elem.get(key) != data.get(key): + return False + return True + -- cgit From 162f1750344a4e1812a15ec132fefd6e1fd47ca5 Mon Sep 17 00:00:00 2001 From: Naveed Massjouni Date: Wed, 31 Aug 2011 18:38:55 -0400 Subject: Updating test for xml to use lxml. --- nova/tests/api/openstack/test_versions.py | 61 ++++++++++++++++--------------- 1 file changed, 32 insertions(+), 29 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_versions.py b/nova/tests/api/openstack/test_versions.py index 129d1e69d..03a47bf24 100644 --- a/nova/tests/api/openstack/test_versions.py +++ b/nova/tests/api/openstack/test_versions.py @@ -483,28 +483,32 @@ class VersionsTest(test.TestCase): self.assertEqual(res.status_int, 300) self.assertEqual(res.content_type, "application/xml") - expected = """ - - - - - - - - - - - - - - - - """.replace(" ", "").replace("\n", "") % (wsgi.XMLNS_V11, - wsgi.XMLNS_ATOM) + root = etree.XML(res.body) + self.assertTrue(root.xpath('/ns:choices', namespaces=NS)) + versions = root.xpath('ns:version', namespaces=NS) + self.assertEqual(len(versions), 2) + + version = versions[0] + self.assertEqual(version.get('id'), 'v1.1'); + self.assertEqual(version.get('status'), 'CURRENT') + media_types = version.xpath('ns:media-types/ns:media-type', + namespaces=NS) + self.assertTrue(_compare_media_types(media_types, + VERSIONS['v1.1']['media-types'])) + links = version.xpath('atom:link', namespaces=NS) + self.assertTrue(_compare_links(links, + [{'rel': 'self', 'href': 'http://localhost/v1.1/images/1'}])) + + version = versions[1] + self.assertEqual(version.get('id'), 'v1.0'); + self.assertEqual(version.get('status'), 'DEPRECATED') + media_types = version.xpath('ns:media-types/ns:media-type', + namespaces=NS) + self.assertTrue(_compare_media_types(media_types, + VERSIONS['v1.0']['media-types'])) + links = version.xpath('atom:link', namespaces=NS) + self.assertTrue(_compare_links(links, + [{'rel': 'self', 'href': 'http://localhost/v1.0/images/1'}])) def test_multi_choice_server_atom(self): """ @@ -876,17 +880,16 @@ class VersionsSerializerTests(test.TestCase): def _compare_links(actual, expected): - for elem, data in zip(actual, expected): - for key in ('rel', 'href', 'type'): - if elem.get(key) != data.get(key): - return False - return True + return _compare_tree_to_dict(actual, expected, ('rel', 'href', 'type')) def _compare_media_types(actual, expected): + return _compare_tree_to_dict(actual, expected, ('base', 'type')) + + +def _compare_tree_to_dict(actual, expected, keys): for elem, data in zip(actual, expected): - for key in ('base', 'type'): + for key in keys: if elem.get(key) != data.get(key): return False return True - -- cgit From 13c74c252b0b7f900cde6a09201ea01c389f73a8 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Wed, 31 Aug 2011 22:43:26 -0400 Subject: move GlanceImageService tests to proper module; remove translation of non-standard image attributes to properties; ensure all image properties are available, defaulting to None if not provided --- nova/tests/api/openstack/test_images.py | 279 +--------------------------- nova/tests/image/test_glance.py | 318 +++++++++++++++++++++++++++++++- 2 files changed, 315 insertions(+), 282 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_images.py b/nova/tests/api/openstack/test_images.py index 2a7cfc382..b9bd18eda 100644 --- a/nova/tests/api/openstack/test_images.py +++ b/nova/tests/api/openstack/test_images.py @@ -41,280 +41,7 @@ from nova.api.openstack import images from nova.tests.api.openstack import fakes -class _BaseImageServiceTests(test.TestCase): - """Tasks to test for all image services""" - - def __init__(self, *args, **kwargs): - super(_BaseImageServiceTests, self).__init__(*args, **kwargs) - self.service = None - self.context = None - - def test_create(self): - fixture = self._make_fixture('test image') - num_images = len(self.service.index(self.context)) - - image_id = self.service.create(self.context, fixture)['id'] - - self.assertNotEquals(None, image_id) - self.assertEquals(num_images + 1, - len(self.service.index(self.context))) - - def test_create_and_show_non_existing_image(self): - fixture = self._make_fixture('test image') - num_images = len(self.service.index(self.context)) - - image_id = self.service.create(self.context, fixture)['id'] - - self.assertNotEquals(None, image_id) - self.assertRaises(exception.NotFound, - self.service.show, - self.context, - 'bad image id') - - def test_create_and_show_non_existing_image_by_name(self): - fixture = self._make_fixture('test image') - num_images = len(self.service.index(self.context)) - - image_id = self.service.create(self.context, fixture)['id'] - - self.assertNotEquals(None, image_id) - self.assertRaises(exception.ImageNotFound, - self.service.show_by_name, - self.context, - 'bad image id') - - def test_update(self): - fixture = self._make_fixture('test image') - image_id = self.service.create(self.context, fixture)['id'] - fixture['status'] = 'in progress' - - self.service.update(self.context, image_id, fixture) - - new_image_data = self.service.show(self.context, image_id) - self.assertEquals('in progress', new_image_data['status']) - - def test_delete(self): - fixture1 = self._make_fixture('test image 1') - fixture2 = self._make_fixture('test image 2') - fixtures = [fixture1, fixture2] - - num_images = len(self.service.index(self.context)) - self.assertEquals(0, num_images, str(self.service.index(self.context))) - - ids = [] - for fixture in fixtures: - new_id = self.service.create(self.context, fixture)['id'] - ids.append(new_id) - - num_images = len(self.service.index(self.context)) - self.assertEquals(2, num_images, str(self.service.index(self.context))) - - self.service.delete(self.context, ids[0]) - - num_images = len(self.service.index(self.context)) - self.assertEquals(1, num_images) - - def test_index(self): - fixture = self._make_fixture('test image') - image_id = self.service.create(self.context, fixture)['id'] - image_metas = self.service.index(self.context) - expected = [{'id': 'DONTCARE', 'name': 'test image'}] - self.assertDictListMatch(image_metas, expected) - - @staticmethod - def _make_fixture(name): - fixture = {'name': name, - 'updated': None, - 'created': None, - 'status': None, - 'is_public': True} - return fixture - - -class GlanceImageServiceTest(_BaseImageServiceTests): - - """Tests the Glance image service, in particular that metadata translation - works properly. - - At a high level, the translations involved are: - - 1. Glance -> ImageService - This is needed so we can support - multple ImageServices (Glance, Local, etc) - - 2. ImageService -> API - This is needed so we can support multple - APIs (OpenStack, EC2) - """ - def setUp(self): - super(GlanceImageServiceTest, self).setUp() - self.stubs = stubout.StubOutForTesting() - fakes.stub_out_glance(self.stubs) - fakes.stub_out_compute_api_snapshot(self.stubs) - service_class = 'nova.image.glance.GlanceImageService' - self.service = utils.import_object(service_class) - self.context = context.RequestContext('fake', 'fake') - self.service.delete_all() - self.sent_to_glance = {} - fakes.stub_out_glance_add_image(self.stubs, self.sent_to_glance) - - def tearDown(self): - self.stubs.UnsetAll() - super(GlanceImageServiceTest, self).tearDown() - - def test_create_with_instance_id(self): - """Ensure instance_id is persisted as an image-property""" - fixture = {'name': 'test image', - 'is_public': False, - 'properties': {'instance_id': '42', 'user_id': 'fake'}} - - image_id = self.service.create(self.context, fixture)['id'] - expected = fixture - self.assertDictMatch(self.sent_to_glance['metadata'], expected) - - image_meta = self.service.show(self.context, image_id) - expected = {'id': image_id, - 'name': 'test image', - 'is_public': False, - 'properties': {'instance_id': '42', 'user_id': 'fake'}} - self.assertDictMatch(image_meta, expected) - - image_metas = self.service.detail(self.context) - self.assertDictMatch(image_metas[0], expected) - - def test_create_without_instance_id(self): - """ - Ensure we can create an image without having to specify an - instance_id. Public images are an example of an image not tied to an - instance. - """ - fixture = {'name': 'test image'} - image_id = self.service.create(self.context, fixture)['id'] - - expected = {'name': 'test image', 'properties': {}} - self.assertDictMatch(self.sent_to_glance['metadata'], expected) - - def test_index_default_limit(self): - fixtures = [] - ids = [] - for i in range(10): - fixture = self._make_fixture('TestImage %d' % (i)) - fixtures.append(fixture) - ids.append(self.service.create(self.context, fixture)['id']) - - image_metas = self.service.index(self.context) - i = 0 - for meta in image_metas: - expected = {'id': 'DONTCARE', - 'name': 'TestImage %d' % (i)} - self.assertDictMatch(meta, expected) - i = i + 1 - - def test_index_marker(self): - fixtures = [] - ids = [] - for i in range(10): - fixture = self._make_fixture('TestImage %d' % (i)) - fixtures.append(fixture) - ids.append(self.service.create(self.context, fixture)['id']) - - image_metas = self.service.index(self.context, marker=ids[1]) - self.assertEquals(len(image_metas), 8) - i = 2 - for meta in image_metas: - expected = {'id': 'DONTCARE', - 'name': 'TestImage %d' % (i)} - self.assertDictMatch(meta, expected) - i = i + 1 - - def test_index_limit(self): - fixtures = [] - ids = [] - for i in range(10): - fixture = self._make_fixture('TestImage %d' % (i)) - fixtures.append(fixture) - ids.append(self.service.create(self.context, fixture)['id']) - - image_metas = self.service.index(self.context, limit=3) - self.assertEquals(len(image_metas), 3) - - def test_index_marker_and_limit(self): - fixtures = [] - ids = [] - for i in range(10): - fixture = self._make_fixture('TestImage %d' % (i)) - fixtures.append(fixture) - ids.append(self.service.create(self.context, fixture)['id']) - - image_metas = self.service.index(self.context, marker=ids[3], limit=1) - self.assertEquals(len(image_metas), 1) - i = 4 - for meta in image_metas: - expected = {'id': 'DONTCARE', - 'name': 'TestImage %d' % (i)} - self.assertDictMatch(meta, expected) - i = i + 1 - - def test_detail_marker(self): - fixtures = [] - ids = [] - for i in range(10): - fixture = self._make_fixture('TestImage %d' % (i)) - fixtures.append(fixture) - ids.append(self.service.create(self.context, fixture)['id']) - - image_metas = self.service.detail(self.context, marker=ids[1]) - self.assertEquals(len(image_metas), 8) - i = 2 - for meta in image_metas: - expected = { - 'id': 'DONTCARE', - 'status': None, - 'is_public': True, - 'name': 'TestImage %d' % (i), - 'properties': { - 'updated': None, - 'created': None, - }, - } - - self.assertDictMatch(meta, expected) - i = i + 1 - - def test_detail_limit(self): - fixtures = [] - ids = [] - for i in range(10): - fixture = self._make_fixture('TestImage %d' % (i)) - fixtures.append(fixture) - ids.append(self.service.create(self.context, fixture)['id']) - - image_metas = self.service.detail(self.context, limit=3) - self.assertEquals(len(image_metas), 3) - - def test_detail_marker_and_limit(self): - fixtures = [] - ids = [] - for i in range(10): - fixture = self._make_fixture('TestImage %d' % (i)) - fixtures.append(fixture) - ids.append(self.service.create(self.context, fixture)['id']) - - image_metas = self.service.detail(self.context, marker=ids[3], limit=3) - self.assertEquals(len(image_metas), 3) - i = 4 - for meta in image_metas: - expected = { - 'id': 'DONTCARE', - 'status': None, - 'is_public': True, - 'name': 'TestImage %d' % (i), - 'properties': { - 'updated': None, 'created': None}, - } - self.assertDictMatch(meta, expected) - i = i + 1 - - -class ImageControllerWithGlanceServiceTest(test.TestCase): +class ImagesTest(test.TestCase): """ Test of the OpenStack API /images application controller w/Glance. """ @@ -323,7 +50,7 @@ class ImageControllerWithGlanceServiceTest(test.TestCase): def setUp(self): """Run before each test.""" - super(ImageControllerWithGlanceServiceTest, self).setUp() + super(ImagesTest, self).setUp() self.flags(image_service='nova.image.glance.GlanceImageService') self.stubs = stubout.StubOutForTesting() fakes.stub_out_networking(self.stubs) @@ -337,7 +64,7 @@ class ImageControllerWithGlanceServiceTest(test.TestCase): def tearDown(self): """Run after each test.""" self.stubs.UnsetAll() - super(ImageControllerWithGlanceServiceTest, self).tearDown() + super(ImagesTest, self).tearDown() def _get_fake_context(self): class Context(object): diff --git a/nova/tests/image/test_glance.py b/nova/tests/image/test_glance.py index 5df25df37..cee17ba72 100644 --- a/nova/tests/image/test_glance.py +++ b/nova/tests/image/test_glance.py @@ -17,11 +17,15 @@ import datetime +import stubout import unittest +from nova.tests.api.openstack import fakes from nova import context -from nova import test +from nova import exception from nova.image import glance +from nova import test +from nova import utils class StubGlanceClient(object): @@ -91,10 +95,13 @@ class BaseGlanceTest(unittest.TestCase): class TestGlanceImageServiceProperties(BaseGlanceTest): + """ + Ensure attributes which aren't base attributes are ignored. Missing + attributes should be added as None + + """ + def test_show_passes_through_to_client(self): - """Ensure attributes which aren't BASE_IMAGE_ATTRS are stored in the - properties dict - """ fixtures = {'image1': {'id': '1', 'name': 'image1', 'is_public': True, 'foo': 'bar', 'properties': {'prop1': 'propvalue1'}}} @@ -102,7 +109,11 @@ class TestGlanceImageServiceProperties(BaseGlanceTest): image_meta = self.service.show(self.context, 'image1') expected = {'id': '1', 'name': 'image1', 'is_public': True, - 'properties': {'prop1': 'propvalue1', 'foo': 'bar'}} + 'size': None, 'location': None, 'disk_format': None, + 'container_format': None, 'checksum': None, + 'created_at': None, 'updated_at': None, + 'deleted_at': None, 'deleted': None, 'status': None, + 'properties': {'prop1': 'propvalue1'}} self.assertEqual(image_meta, expected) def test_detail_passes_through_to_client(self): @@ -112,7 +123,11 @@ class TestGlanceImageServiceProperties(BaseGlanceTest): self.client.images = fixtures image_meta = self.service.detail(self.context) expected = [{'id': '1', 'name': 'image1', 'is_public': True, - 'properties': {'prop1': 'propvalue1', 'foo': 'bar'}}] + 'size': None, 'location': None, 'disk_format': None, + 'container_format': None, 'checksum': None, + 'created_at': None, 'updated_at': None, + 'deleted_at': None, 'deleted': None, 'status': None, + 'properties': {'prop1': 'propvalue1'}}] self.assertEqual(image_meta, expected) @@ -286,3 +301,294 @@ class TestGlanceSerializer(unittest.TestCase): converted = glance._convert_to_string(metadata) self.assertEqual(converted, converted_expected) self.assertEqual(glance._convert_from_string(converted), metadata) + + +class GlanceImageServiceTest(test.TestCase): + + """Tests the Glance image service, in particular that metadata translation + works properly. + + At a high level, the translations involved are: + + 1. Glance -> ImageService - This is needed so we can support + multple ImageServices (Glance, Local, etc) + + 2. ImageService -> API - This is needed so we can support multple + APIs (OpenStack, EC2) + """ + def __init__(self, *args, **kwargs): + super(GlanceImageServiceTest, self).__init__(*args, **kwargs) + self.service = None + self.context = None + + @staticmethod + def _make_fixture(name): + fixture = {'name': name, + 'properties': {'one': 'two'}, + 'status': None, + 'is_public': True} + return fixture + + def setUp(self): + super(GlanceImageServiceTest, self).setUp() + self.stubs = stubout.StubOutForTesting() + fakes.stub_out_glance(self.stubs) + fakes.stub_out_compute_api_snapshot(self.stubs) + service_class = 'nova.image.glance.GlanceImageService' + self.service = utils.import_object(service_class) + self.context = context.RequestContext('fake', 'fake') + self.service.delete_all() + self.sent_to_glance = {} + fakes.stub_out_glance_add_image(self.stubs, self.sent_to_glance) + + def tearDown(self): + self.stubs.UnsetAll() + super(GlanceImageServiceTest, self).tearDown() + + def test_create_with_instance_id(self): + """Ensure instance_id is persisted as an image-property""" + fixture = {'name': 'test image', + 'is_public': False, + 'properties': {'instance_id': '42', 'user_id': 'fake'}} + + image_id = self.service.create(self.context, fixture)['id'] + expected = fixture + self.assertDictMatch(self.sent_to_glance['metadata'], expected) + + image_meta = self.service.show(self.context, image_id) + expected = {'id': image_id, 'name': 'test image', 'is_public': False, + 'size': None, 'location': None, 'disk_format': None, + 'container_format': None, 'checksum': None, + 'created_at': None, 'updated_at': None, + 'deleted_at': None, 'deleted': None, 'status': None, + 'properties': {'instance_id': '42', 'user_id': 'fake'}} + self.assertDictMatch(image_meta, expected) + + image_metas = self.service.detail(self.context) + self.assertDictMatch(image_metas[0], expected) + + def test_create_without_instance_id(self): + """ + Ensure we can create an image without having to specify an + instance_id. Public images are an example of an image not tied to an + instance. + """ + fixture = {'name': 'test image'} + image_id = self.service.create(self.context, fixture)['id'] + + expected = {'name': 'test image'} + self.assertDictMatch(self.sent_to_glance['metadata'], expected) + + def test_create(self): + fixture = self._make_fixture('test image') + num_images = len(self.service.index(self.context)) + + image_id = self.service.create(self.context, fixture)['id'] + + self.assertNotEquals(None, image_id) + self.assertEquals(num_images + 1, + len(self.service.index(self.context))) + + def test_create_and_show_non_existing_image(self): + fixture = self._make_fixture('test image') + num_images = len(self.service.index(self.context)) + + image_id = self.service.create(self.context, fixture)['id'] + + self.assertNotEquals(None, image_id) + self.assertRaises(exception.NotFound, + self.service.show, + self.context, + 'bad image id') + + def test_create_and_show_non_existing_image_by_name(self): + fixture = self._make_fixture('test image') + num_images = len(self.service.index(self.context)) + + image_id = self.service.create(self.context, fixture)['id'] + + self.assertNotEquals(None, image_id) + self.assertRaises(exception.ImageNotFound, + self.service.show_by_name, + self.context, + 'bad image id') + + def test_index(self): + fixture = self._make_fixture('test image') + image_id = self.service.create(self.context, fixture)['id'] + image_metas = self.service.index(self.context) + expected = [{'id': 'DONTCARE', 'name': 'test image'}] + self.assertDictListMatch(image_metas, expected) + + def test_index_default_limit(self): + fixtures = [] + ids = [] + for i in range(10): + fixture = self._make_fixture('TestImage %d' % (i)) + fixtures.append(fixture) + ids.append(self.service.create(self.context, fixture)['id']) + + image_metas = self.service.index(self.context) + i = 0 + for meta in image_metas: + expected = {'id': 'DONTCARE', + 'name': 'TestImage %d' % (i)} + self.assertDictMatch(meta, expected) + i = i + 1 + + def test_index_marker(self): + fixtures = [] + ids = [] + for i in range(10): + fixture = self._make_fixture('TestImage %d' % (i)) + fixtures.append(fixture) + ids.append(self.service.create(self.context, fixture)['id']) + + image_metas = self.service.index(self.context, marker=ids[1]) + self.assertEquals(len(image_metas), 8) + i = 2 + for meta in image_metas: + expected = {'id': 'DONTCARE', + 'name': 'TestImage %d' % (i)} + self.assertDictMatch(meta, expected) + i = i + 1 + + def test_index_limit(self): + fixtures = [] + ids = [] + for i in range(10): + fixture = self._make_fixture('TestImage %d' % (i)) + fixtures.append(fixture) + ids.append(self.service.create(self.context, fixture)['id']) + + image_metas = self.service.index(self.context, limit=3) + self.assertEquals(len(image_metas), 3) + + def test_index_marker_and_limit(self): + fixtures = [] + ids = [] + for i in range(10): + fixture = self._make_fixture('TestImage %d' % (i)) + fixtures.append(fixture) + ids.append(self.service.create(self.context, fixture)['id']) + + image_metas = self.service.index(self.context, marker=ids[3], limit=1) + self.assertEquals(len(image_metas), 1) + i = 4 + for meta in image_metas: + expected = {'id': 'DONTCARE', + 'name': 'TestImage %d' % (i)} + self.assertDictMatch(meta, expected) + i = i + 1 + + def test_detail_marker(self): + fixtures = [] + ids = [] + for i in range(10): + fixture = self._make_fixture('TestImage %d' % (i)) + fixtures.append(fixture) + ids.append(self.service.create(self.context, fixture)['id']) + + image_metas = self.service.detail(self.context, marker=ids[1]) + self.assertEquals(len(image_metas), 8) + i = 2 + for meta in image_metas: + expected = { + 'id': 'DONTCARE', + 'status': None, + 'is_public': True, + 'name': 'TestImage %d' % (i), + 'properties': {'one': 'two'}, + 'size': None, + 'location': None, + 'disk_format': None, + 'container_format': None, + 'checksum': None, + 'created_at': None, + 'updated_at': None, + 'deleted_at': None, + 'deleted': None + } + + print meta + print expected + self.assertDictMatch(meta, expected) + i = i + 1 + + def test_detail_limit(self): + fixtures = [] + ids = [] + for i in range(10): + fixture = self._make_fixture('TestImage %d' % (i)) + fixtures.append(fixture) + ids.append(self.service.create(self.context, fixture)['id']) + + image_metas = self.service.detail(self.context, limit=3) + self.assertEquals(len(image_metas), 3) + + def test_detail_marker_and_limit(self): + fixtures = [] + ids = [] + for i in range(10): + fixture = self._make_fixture('TestImage %d' % (i)) + fixtures.append(fixture) + ids.append(self.service.create(self.context, fixture)['id']) + + image_metas = self.service.detail(self.context, marker=ids[3], limit=3) + self.assertEquals(len(image_metas), 3) + i = 4 + for meta in image_metas: + expected = { + 'id': 'DONTCARE', + 'status': None, + 'is_public': True, + 'name': 'TestImage %d' % (i), + 'properties': {'one': 'two'}, + 'size': None, + 'location': None, + 'disk_format': None, + 'container_format': None, + 'checksum': None, + 'created_at': None, + 'updated_at': None, + 'deleted_at': None, + 'deleted': None + } + self.assertDictMatch(meta, expected) + i = i + 1 + + + def test_update(self): + fixture = self._make_fixture('test image') + image_id = self.service.create(self.context, fixture)['id'] + fixture['status'] = 'in progress' + + self.service.update(self.context, image_id, fixture) + + new_image_data = self.service.show(self.context, image_id) + self.assertEquals('in progress', new_image_data['status']) + + def test_delete(self): + fixture1 = self._make_fixture('test image 1') + fixture2 = self._make_fixture('test image 2') + fixtures = [fixture1, fixture2] + + num_images = len(self.service.index(self.context)) + self.assertEquals(0, num_images, str(self.service.index(self.context))) + + ids = [] + for fixture in fixtures: + new_id = self.service.create(self.context, fixture)['id'] + ids.append(new_id) + + num_images = len(self.service.index(self.context)) + self.assertEquals(2, num_images, str(self.service.index(self.context))) + + self.service.delete(self.context, ids[0]) + + num_images = len(self.service.index(self.context)) + self.assertEquals(1, num_images) + + + + -- cgit From 62e2ad123685ab01accfb9988013225fe377dfbe Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Wed, 31 Aug 2011 23:07:07 -0400 Subject: pep8 --- nova/tests/image/test_glance.py | 5 ----- 1 file changed, 5 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/image/test_glance.py b/nova/tests/image/test_glance.py index cee17ba72..3922036a9 100644 --- a/nova/tests/image/test_glance.py +++ b/nova/tests/image/test_glance.py @@ -557,7 +557,6 @@ class GlanceImageServiceTest(test.TestCase): self.assertDictMatch(meta, expected) i = i + 1 - def test_update(self): fixture = self._make_fixture('test image') image_id = self.service.create(self.context, fixture)['id'] @@ -588,7 +587,3 @@ class GlanceImageServiceTest(test.TestCase): num_images = len(self.service.index(self.context)) self.assertEquals(1, num_images) - - - - -- cgit From b63b6d896917af60fcc1b76b22cb912faab3c1c3 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Wed, 31 Aug 2011 23:26:18 -0400 Subject: removing unnecessary imports --- nova/tests/api/openstack/test_images.py | 6 ------ 1 file changed, 6 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_images.py b/nova/tests/api/openstack/test_images.py index b9bd18eda..942bab5c7 100644 --- a/nova/tests/api/openstack/test_images.py +++ b/nova/tests/api/openstack/test_images.py @@ -22,20 +22,14 @@ and as a WSGI layer import copy import json -import os -import shutil -import tempfile import xml.dom.minidom as minidom import mox import stubout import webob -from glance import client as glance_client from nova import context -from nova import exception from nova import test -from nova import utils import nova.api.openstack from nova.api.openstack import images from nova.tests.api.openstack import fakes -- cgit From 26e581ac03336182a44f2a411f28da36beef0f89 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Thu, 1 Sep 2011 11:40:44 -0400 Subject: docstring cleanup --- nova/tests/image/test_glance.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/image/test_glance.py b/nova/tests/image/test_glance.py index 3922036a9..4b7e04d7c 100644 --- a/nova/tests/image/test_glance.py +++ b/nova/tests/image/test_glance.py @@ -96,8 +96,9 @@ class BaseGlanceTest(unittest.TestCase): class TestGlanceImageServiceProperties(BaseGlanceTest): """ - Ensure attributes which aren't base attributes are ignored. Missing - attributes should be added as None + Ensure attributes which aren't base attributes are ignored. + + Missingattributes should be added as None """ @@ -304,9 +305,8 @@ class TestGlanceSerializer(unittest.TestCase): class GlanceImageServiceTest(test.TestCase): - - """Tests the Glance image service, in particular that metadata translation - works properly. + """ + Tests the Glance image service. At a high level, the translations involved are: @@ -315,6 +315,7 @@ class GlanceImageServiceTest(test.TestCase): 2. ImageService -> API - This is needed so we can support multple APIs (OpenStack, EC2) + """ def __init__(self, *args, **kwargs): super(GlanceImageServiceTest, self).__init__(*args, **kwargs) -- cgit From 0c737cb60980b8db74496e7914322f567950c2c3 Mon Sep 17 00:00:00 2001 From: Naveed Massjouni Date: Fri, 2 Sep 2011 01:07:30 -0400 Subject: Removing xml functions that are no longer called. --- nova/tests/api/openstack/test_versions.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_versions.py b/nova/tests/api/openstack/test_versions.py index 03a47bf24..a9308e31d 100644 --- a/nova/tests/api/openstack/test_versions.py +++ b/nova/tests/api/openstack/test_versions.py @@ -306,7 +306,8 @@ class VersionsTest(test.TestCase): self.assertEqual(f.feed.updated, '2011-01-21T11:33:21Z') self.assertEqual(f.feed.id, 'http://localhost/v1.0/') self.assertEqual(f.feed.author, 'Rackspace') - self.assertEqual(f.feed.author_detail.href, 'http://www.rackspace.com/') + self.assertEqual(f.feed.author_detail.href, + 'http://www.rackspace.com/') self.assertEqual(f.feed.links, [{'href': 'http://localhost/v1.0/', 'type': 'application/atom+xml', 'rel': 'self'}]) @@ -350,7 +351,8 @@ class VersionsTest(test.TestCase): self.assertEqual(f.feed.updated, '2011-01-21T11:33:21Z') self.assertEqual(f.feed.id, 'http://localhost/v1.1/') self.assertEqual(f.feed.author, 'Rackspace') - self.assertEqual(f.feed.author_detail.href, 'http://www.rackspace.com/') + self.assertEqual(f.feed.author_detail.href, + 'http://www.rackspace.com/') self.assertEqual(f.feed.links, [{'href': 'http://localhost/v1.1/', 'type': 'application/atom+xml', 'rel': 'self'}]) @@ -394,7 +396,8 @@ class VersionsTest(test.TestCase): self.assertEqual(f.feed.updated, '2011-01-21T11:33:21Z') self.assertEqual(f.feed.id, 'http://localhost/') self.assertEqual(f.feed.author, 'Rackspace') - self.assertEqual(f.feed.author_detail.href, 'http://www.rackspace.com/') + self.assertEqual(f.feed.author_detail.href, + 'http://www.rackspace.com/') self.assertEqual(f.feed.links, [{'href': 'http://localhost/', 'type': 'application/atom+xml', 'rel': 'self'}]) @@ -489,7 +492,7 @@ class VersionsTest(test.TestCase): self.assertEqual(len(versions), 2) version = versions[0] - self.assertEqual(version.get('id'), 'v1.1'); + self.assertEqual(version.get('id'), 'v1.1') self.assertEqual(version.get('status'), 'CURRENT') media_types = version.xpath('ns:media-types/ns:media-type', namespaces=NS) @@ -500,7 +503,7 @@ class VersionsTest(test.TestCase): [{'rel': 'self', 'href': 'http://localhost/v1.1/images/1'}])) version = versions[1] - self.assertEqual(version.get('id'), 'v1.0'); + self.assertEqual(version.get('id'), 'v1.0') self.assertEqual(version.get('status'), 'DEPRECATED') media_types = version.xpath('ns:media-types/ns:media-type', namespaces=NS) @@ -784,7 +787,8 @@ class VersionsSerializerTests(test.TestCase): self.assertEqual(f.feed.updated, '2011-07-20T11:40:00Z') self.assertEqual(f.feed.id, 'http://test/') self.assertEqual(f.feed.author, 'Rackspace') - self.assertEqual(f.feed.author_detail.href, 'http://www.rackspace.com/') + self.assertEqual(f.feed.author_detail.href, + 'http://www.rackspace.com/') self.assertEqual(f.feed.links, [{'href': 'http://test/', 'type': 'application/atom+xml', 'rel': 'self'}]) @@ -846,7 +850,8 @@ class VersionsSerializerTests(test.TestCase): self.assertEqual(f.feed.updated, '2011-01-21T11:33:21Z') self.assertEqual(f.feed.id, 'http://localhost/v1.1/') self.assertEqual(f.feed.author, 'Rackspace') - self.assertEqual(f.feed.author_detail.href, 'http://www.rackspace.com/') + self.assertEqual(f.feed.author_detail.href, + 'http://www.rackspace.com/') self.assertEqual(f.feed.links, [{'href': 'http://localhost/v1.1/', 'type': 'application/atom+xml', 'rel': 'self'}]) -- cgit From 9b35957eef001ae1c3329e9197984d3aca0da787 Mon Sep 17 00:00:00 2001 From: Naveed Massjouni Date: Sun, 4 Sep 2011 05:39:21 -0400 Subject: Fixing xml serialization of limits resource. --- nova/tests/api/openstack/test_limits.py | 34 ++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_limits.py b/nova/tests/api/openstack/test_limits.py index f71d9c454..3db57ee86 100644 --- a/nova/tests/api/openstack/test_limits.py +++ b/nova/tests/api/openstack/test_limits.py @@ -41,8 +41,10 @@ TEST_LIMITS = [ limits.Limit("PUT", "*", "", 10, limits.PER_MINUTE), limits.Limit("PUT", "/servers", "^/servers", 5, limits.PER_MINUTE), ] -NS = "{http://docs.openstack.org/compute/api/v1.1}" -ATOMNS = "{http://www.w3.org/2005/Atom}" +NS = { + 'atom': 'http://www.w3.org/2005/Atom', + 'ns': 'http://docs.openstack.org/compute/api/v1.1' +} class BaseLimitTestSuite(unittest.TestCase): @@ -998,7 +1000,8 @@ class LimitsXMLSerializationTest(test.TestCase): def test_index(self): serializer = limits.LimitsXMLSerializer() - fixture = {"limits": { + fixture = { + "limits": { "rate": [{ "uri": "*", "regex": ".*", @@ -1027,28 +1030,27 @@ class LimitsXMLSerializationTest(test.TestCase): xmlutil.validate_schema(root, 'limits') #verify absolute limits - absolute = root.find('{0}absolute'.format(NS)) - absolutes = absolute.findall('limit'.format(NS)) + absolutes = root.xpath('ns:absolute/ns:limit', namespaces=NS) + self.assertEqual(len(absolutes), 4) for limit in absolutes: name = limit.get('name') value = limit.get('value') self.assertEqual(value, str(fixture['limits']['absolute'][name])) #verify rate limits - rate_root = root.find('{0}rates'.format(NS)) - rates = rate_root.findall('{0}rate'.format(NS)) - for i in range(len(rates)): - rate = rates[i] + rates = root.xpath('ns:rates/ns:rate', namespaces=NS) + self.assertEqual(len(rates), 2) + for i, rate in enumerate(rates): for key in ['uri', 'regex']: self.assertEqual(rate.get(key), str(fixture['limits']['rate'][i][key])) - rate_limits = rate.findall('{0}limit'.format(NS)) - for z in range(len(rate_limits)): - limit = rate_limits[z] + rate_limits = rate.xpath('ns:limit', namespaces=NS) + self.assertEqual(len(rate_limits), 1) + for j, limit in enumerate(rate_limits): for key in ['verb', 'value', 'remaining', 'unit', 'next-available']: self.assertEqual(limit.get(key), - str(fixture['limits']['rate'][i]['limit'][z][key])) + str(fixture['limits']['rate'][i]['limit'][j][key])) def test_index_no_limits(self): serializer = limits.LimitsXMLSerializer() @@ -1063,11 +1065,9 @@ class LimitsXMLSerializationTest(test.TestCase): xmlutil.validate_schema(root, 'limits') #verify absolute limits - absolute = root.find('{0}absolute'.format(NS)) - absolutes = absolute.findall('limit'.format(NS)) + absolutes = root.xpath('ns:absolute/ns:limit', namespaces=NS) self.assertEqual(len(absolutes), 0) #verify rate limits - rate_root = root.find('{0}rates'.format(NS)) - rates = rate_root.findall('{0}rate'.format(NS)) + rates = root.xpath('ns:rates/ns:rate', namespaces=NS) self.assertEqual(len(rates), 0) -- cgit From d155f4224cb97e43cacd4102ba01f0e1775dfbdf Mon Sep 17 00:00:00 2001 From: Naveed Massjouni Date: Sun, 4 Sep 2011 05:39:59 -0400 Subject: Minor cleanup. --- nova/tests/api/openstack/test_versions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_versions.py b/nova/tests/api/openstack/test_versions.py index a9308e31d..8b60db71e 100644 --- a/nova/tests/api/openstack/test_versions.py +++ b/nova/tests/api/openstack/test_versions.py @@ -285,7 +285,7 @@ class VersionsTest(test.TestCase): versions = root.xpath('ns:version', namespaces=NS) self.assertEqual(len(versions), 2) - for (i, v) in ((0, 'v1.0'), (1, 'v1.1')): + for i, v in enumerate(['v1.0', 'v1.1']): version = versions[i] expected = VERSIONS[v] for key in ['id', 'status', 'updated']: -- cgit From c87009f009cb749dbccd6bd155ec1a6800631ae1 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 6 Sep 2011 09:24:24 -0400 Subject: cleaning up tests --- nova/tests/image/test_glance.py | 549 ++++++++++++++++++---------------------- 1 file changed, 249 insertions(+), 300 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/image/test_glance.py b/nova/tests/image/test_glance.py index e4324d24b..f77117ca0 100644 --- a/nova/tests/image/test_glance.py +++ b/nova/tests/image/test_glance.py @@ -18,20 +18,18 @@ import datetime import stubout -import unittest from nova.tests.api.openstack import fakes from nova import context from nova import exception from nova.image import glance from nova import test -from nova import utils class StubGlanceClient(object): - def __init__(self, images, add_response=None, update_response=None): - self.images = images + def __init__(self, images=None, add_response=None, update_response=None): + self.images = images or [] self.add_response = add_response self.update_response = update_response @@ -39,28 +37,51 @@ class StubGlanceClient(object): pass def get_image_meta(self, image_id): - return self.images[image_id] + for image in self.images: + if image['id'] == image_id: + return image + raise exception.ImageNotFound(image_id=image_id) - def get_images_detailed(self, filters=None, marker=None, limit=None): - images = self.images.values() + #TODO(bcwaldon): implement filters + def get_images_detailed(self, filters=None, marker=None, limit=3): if marker is None: index = 0 else: - for index, image in enumerate(images): + for index, image in enumerate(self.images): if image['id'] == marker: index += 1 break - # default to a page size of 3 to ensure we flex the pagination code - return images[index:index + 3] + + return self.images[index:index + limit] def get_image(self, image_id): - return self.images[image_id], [] + return self.get_image_meta(image_id), [] def add_image(self, metadata, data): - return self.add_response + self.images.append(metadata) + + try: + image_id = int(metadata['id']) + except KeyError: + # auto-generate an id if one wasn't provided + image_id = len(self.images) + metadata['id'] = image_id + + return metadata def update_image(self, image_id, metadata, data): - return self.update_response + for i, image in enumerate(self.images): + if image['id'] == image_id: + self.images[i].update(metadata) + return self.images[i] + raise exception.ImageNotFound(image_id=image_id) + + def delete_image(self, image_id): + for i, image in enumerate(self.images): + if image['id'] == image_id: + del self.images[i] + return + raise exception.ImageNotFound(image_id=image_id) class NullWriter(object): @@ -70,230 +91,7 @@ class NullWriter(object): pass -class BaseGlanceTest(unittest.TestCase): - NOW_GLANCE_OLD_FORMAT = "2010-10-11T10:30:22" - NOW_GLANCE_FORMAT = "2010-10-11T10:30:22.000000" - NOW_DATETIME = datetime.datetime(2010, 10, 11, 10, 30, 22) - - def setUp(self): - self.client = StubGlanceClient(None) - self.service = glance.GlanceImageService(client=self.client) - self.context = context.RequestContext(None, None) - - def assertDateTimesFilled(self, image_meta): - self.assertEqual(image_meta['created_at'], self.NOW_DATETIME) - self.assertEqual(image_meta['updated_at'], self.NOW_DATETIME) - self.assertEqual(image_meta['deleted_at'], self.NOW_DATETIME) - - def assertDateTimesEmpty(self, image_meta): - self.assertEqual(image_meta['updated_at'], None) - self.assertEqual(image_meta['deleted_at'], None) - - def assertDateTimesBlank(self, image_meta): - self.assertEqual(image_meta['updated_at'], '') - self.assertEqual(image_meta['deleted_at'], '') - - -class TestGlanceImageServiceProperties(BaseGlanceTest): - """ - Ensure attributes which aren't base attributes are ignored. - - Missingattributes should be added as None - - """ - - def test_show_passes_through_to_client(self): - fixtures = {'image1': {'id': '1', 'name': 'image1', 'is_public': True, - 'foo': 'bar', - 'properties': {'prop1': 'propvalue1'}}} - self.client.images = fixtures - image_meta = self.service.show(self.context, 'image1') - - expected = {'id': '1', 'name': 'image1', 'is_public': True, - 'size': None, 'location': None, 'disk_format': None, - 'container_format': None, 'checksum': None, - 'created_at': None, 'updated_at': None, - 'deleted_at': None, 'deleted': None, 'status': None, - 'properties': {'prop1': 'propvalue1'}} - self.assertEqual(image_meta, expected) - - def test_show_raises_when_no_authtoken_in_the_context(self): - fixtures = {'image1': {'name': 'image1', 'is_public': False, - 'foo': 'bar', - 'properties': {'prop1': 'propvalue1'}}} - self.client.images = fixtures - self.context.auth_token = False - - expected = {'name': 'image1', 'is_public': True, - 'properties': {'prop1': 'propvalue1', 'foo': 'bar'}} - self.assertRaises(exception.ImageNotFound, - self.service.show, self.context, 'image1') - - def test_show_passes_through_to_client_with_authtoken_in_context(self): - fixtures = {'image1': {'name': 'image1', 'is_public': False, - 'foo': 'bar', - 'properties': {'prop1': 'propvalue1'}}} - self.client.images = fixtures - self.context.auth_token = True - - expected = {'name': 'image1', 'is_public': False, - 'properties': {'prop1': 'propvalue1', 'foo': 'bar'}} - - image_meta = self.service.show(self.context, 'image1') - self.assertEqual(image_meta, expected) - - def test_detail_passes_through_to_client(self): - fixtures = {'image1': {'id': '1', 'name': 'image1', 'is_public': True, - 'foo': 'bar', - 'properties': {'prop1': 'propvalue1'}}} - self.client.images = fixtures - image_meta = self.service.detail(self.context) - expected = [{'id': '1', 'name': 'image1', 'is_public': True, - 'size': None, 'location': None, 'disk_format': None, - 'container_format': None, 'checksum': None, - 'created_at': None, 'updated_at': None, - 'deleted_at': None, 'deleted': None, 'status': None, - 'properties': {'prop1': 'propvalue1'}}] - self.assertEqual(image_meta, expected) - - -class TestGetterDateTimeNoneTests(BaseGlanceTest): - - def test_show_handles_none_datetimes(self): - self.client.images = self._make_none_datetime_fixtures() - image_meta = self.service.show(self.context, 'image1') - self.assertDateTimesEmpty(image_meta) - - def test_show_handles_blank_datetimes(self): - self.client.images = self._make_blank_datetime_fixtures() - image_meta = self.service.show(self.context, 'image1') - self.assertDateTimesBlank(image_meta) - - def test_detail_handles_none_datetimes(self): - self.client.images = self._make_none_datetime_fixtures() - image_meta = self.service.detail(self.context)[0] - self.assertDateTimesEmpty(image_meta) - - def test_detail_handles_blank_datetimes(self): - self.client.images = self._make_blank_datetime_fixtures() - image_meta = self.service.detail(self.context)[0] - self.assertDateTimesBlank(image_meta) - - def test_get_handles_none_datetimes(self): - self.client.images = self._make_none_datetime_fixtures() - writer = NullWriter() - image_meta = self.service.get(self.context, 'image1', writer) - self.assertDateTimesEmpty(image_meta) - - def test_get_handles_blank_datetimes(self): - self.client.images = self._make_blank_datetime_fixtures() - writer = NullWriter() - image_meta = self.service.get(self.context, 'image1', writer) - self.assertDateTimesBlank(image_meta) - - def test_show_makes_datetimes(self): - self.client.images = self._make_datetime_fixtures() - image_meta = self.service.show(self.context, 'image1') - self.assertDateTimesFilled(image_meta) - image_meta = self.service.show(self.context, 'image2') - self.assertDateTimesFilled(image_meta) - - def test_detail_makes_datetimes(self): - self.client.images = self._make_datetime_fixtures() - image_meta = self.service.detail(self.context)[0] - self.assertDateTimesFilled(image_meta) - image_meta = self.service.detail(self.context)[1] - self.assertDateTimesFilled(image_meta) - - def test_get_makes_datetimes(self): - self.client.images = self._make_datetime_fixtures() - writer = NullWriter() - image_meta = self.service.get(self.context, 'image1', writer) - self.assertDateTimesFilled(image_meta) - image_meta = self.service.get(self.context, 'image2', writer) - self.assertDateTimesFilled(image_meta) - - def _make_datetime_fixtures(self): - fixtures = { - 'image1': { - 'id': '1', - 'name': 'image1', - 'is_public': True, - 'created_at': self.NOW_GLANCE_FORMAT, - 'updated_at': self.NOW_GLANCE_FORMAT, - 'deleted_at': self.NOW_GLANCE_FORMAT, - }, - 'image2': { - 'id': '2', - 'name': 'image2', - 'is_public': True, - 'created_at': self.NOW_GLANCE_OLD_FORMAT, - 'updated_at': self.NOW_GLANCE_OLD_FORMAT, - 'deleted_at': self.NOW_GLANCE_OLD_FORMAT, - }, - } - return fixtures - - def _make_none_datetime_fixtures(self): - fixtures = {'image1': {'id': '1', - 'name': 'image1', - 'is_public': True, - 'updated_at': None, - 'deleted_at': None}} - return fixtures - - def _make_blank_datetime_fixtures(self): - fixtures = {'image1': {'id': '1', - 'name': 'image1', - 'is_public': True, - 'updated_at': '', - 'deleted_at': ''}} - return fixtures - - -class TestMutatorDateTimeTests(BaseGlanceTest): - """Tests create(), update()""" - - def test_create_handles_datetimes(self): - self.client.add_response = self._make_datetime_fixture() - image_meta = self.service.create(self.context, {}) - self.assertDateTimesFilled(image_meta) - - def test_create_handles_none_datetimes(self): - self.client.add_response = self._make_none_datetime_fixture() - dummy_meta = {} - image_meta = self.service.create(self.context, dummy_meta) - self.assertDateTimesEmpty(image_meta) - - def test_update_handles_datetimes(self): - self.client.images = {'image1': self._make_datetime_fixture()} - self.client.update_response = self._make_datetime_fixture() - dummy_meta = {} - image_meta = self.service.update(self.context, 'image1', dummy_meta) - self.assertDateTimesFilled(image_meta) - - def test_update_handles_none_datetimes(self): - self.client.images = {'image1': self._make_datetime_fixture()} - self.client.update_response = self._make_none_datetime_fixture() - dummy_meta = {} - image_meta = self.service.update(self.context, 'image1', dummy_meta) - self.assertDateTimesEmpty(image_meta) - - def _make_datetime_fixture(self): - fixture = {'id': 'image1', 'name': 'image1', 'is_public': True, - 'created_at': self.NOW_GLANCE_FORMAT, - 'updated_at': self.NOW_GLANCE_FORMAT, - 'deleted_at': self.NOW_GLANCE_FORMAT} - return fixture - - def _make_none_datetime_fixture(self): - fixture = {'id': 'image1', 'name': 'image1', 'is_public': True, - 'updated_at': None, - 'deleted_at': None} - return fixture - - -class TestGlanceSerializer(unittest.TestCase): +class TestGlanceSerializer(test.TestCase): def test_serialize(self): metadata = {'name': 'image1', 'is_public': True, @@ -329,7 +127,7 @@ class TestGlanceSerializer(unittest.TestCase): self.assertEqual(glance._convert_from_string(converted), metadata) -class GlanceImageServiceTest(test.TestCase): +class TestGlanceImageService(test.TestCase): """ Tests the Glance image service. @@ -342,34 +140,74 @@ class GlanceImageServiceTest(test.TestCase): APIs (OpenStack, EC2) """ - def __init__(self, *args, **kwargs): - super(GlanceImageServiceTest, self).__init__(*args, **kwargs) - self.service = None - self.context = None - - @staticmethod - def _make_fixture(name): - fixture = {'name': name, - 'properties': {'one': 'two'}, - 'status': None, - 'is_public': True} - return fixture + NOW_GLANCE_OLD_FORMAT = "2010-10-11T10:30:22" + NOW_GLANCE_FORMAT = "2010-10-11T10:30:22.000000" + NOW_DATETIME = datetime.datetime(2010, 10, 11, 10, 30, 22) def setUp(self): - super(GlanceImageServiceTest, self).setUp() + super(TestGlanceImageService, self).setUp() self.stubs = stubout.StubOutForTesting() fakes.stub_out_glance(self.stubs) fakes.stub_out_compute_api_snapshot(self.stubs) - service_class = 'nova.image.glance.GlanceImageService' - self.service = utils.import_object(service_class) - self.context = context.RequestContext('fake', 'fake') + self.client = StubGlanceClient() + self.service = glance.GlanceImageService(client=self.client) + self.context = context.RequestContext('fake', 'fake', auth_token=True) self.service.delete_all() - self.sent_to_glance = {} - fakes.stub_out_glance_add_image(self.stubs, self.sent_to_glance) def tearDown(self): self.stubs.UnsetAll() - super(GlanceImageServiceTest, self).tearDown() + super(TestGlanceImageService, self).tearDown() + + + @staticmethod + def _make_fixture(**kwargs): + fixture = {'name': None, + 'properties': {}, + 'status': None, + 'is_public': None} + fixture.update(kwargs) + return fixture + + def _make_datetime_fixtures(self): + return [ + { + 'id': '1', + 'name': 'image1', + 'is_public': True, + 'created_at': self.NOW_GLANCE_FORMAT, + 'updated_at': self.NOW_GLANCE_FORMAT, + 'deleted_at': self.NOW_GLANCE_FORMAT, + }, + { + 'id': '2', + 'name': 'image2', + 'is_public': True, + 'created_at': self.NOW_GLANCE_OLD_FORMAT, + 'updated_at': self.NOW_GLANCE_OLD_FORMAT, + 'deleted_at': self.NOW_GLANCE_OLD_FORMAT, + }, + ] + + def _make_datetime_fixture(self): + return self._make_fixture(created_at=self.NOW_GLANCE_FORMAT, + updated_at=self.NOW_GLANCE_FORMAT, + deleted_at=self.NOW_GLANCE_FORMAT) + + def _make_none_datetime_fixture(self): + return self._make_fixture(updated_at=None, deleted_at=None) + + def assertDateTimesFilled(self, image_meta): + self.assertEqual(image_meta['created_at'], self.NOW_DATETIME) + self.assertEqual(image_meta['updated_at'], self.NOW_DATETIME) + self.assertEqual(image_meta['deleted_at'], self.NOW_DATETIME) + + def assertDateTimesEmpty(self, image_meta): + self.assertEqual(image_meta['updated_at'], None) + self.assertEqual(image_meta['deleted_at'], None) + + def assertDateTimesBlank(self, image_meta): + self.assertEqual(image_meta['updated_at'], '') + self.assertEqual(image_meta['deleted_at'], '') def test_create_with_instance_id(self): """Ensure instance_id is persisted as an image-property""" @@ -378,8 +216,6 @@ class GlanceImageServiceTest(test.TestCase): 'properties': {'instance_id': '42', 'user_id': 'fake'}} image_id = self.service.create(self.context, fixture)['id'] - expected = fixture - self.assertDictMatch(self.sent_to_glance['metadata'], expected) image_meta = self.service.show(self.context, image_id) expected = {'id': image_id, 'name': 'test image', 'is_public': False, @@ -399,16 +235,21 @@ class GlanceImageServiceTest(test.TestCase): instance_id. Public images are an example of an image not tied to an instance. """ - fixture = {'name': 'test image'} + fixture = {'name': 'test image', 'is_public': False} image_id = self.service.create(self.context, fixture)['id'] - expected = {'name': 'test image'} - self.assertDictMatch(self.sent_to_glance['metadata'], expected) + expected = {'id': image_id, 'name': 'test image', 'is_public': False, + 'size': None, 'location': None, 'disk_format': None, + 'container_format': None, 'checksum': None, + 'created_at': None, 'updated_at': None, + 'deleted_at': None, 'deleted': None, 'status': None, + 'properties': {}} + actual = self.service.show(self.context, image_id) + self.assertDictMatch(actual, expected) def test_create(self): - fixture = self._make_fixture('test image') + fixture = self._make_fixture(name='test image') num_images = len(self.service.index(self.context)) - image_id = self.service.create(self.context, fixture)['id'] self.assertNotEquals(None, image_id) @@ -416,9 +257,7 @@ class GlanceImageServiceTest(test.TestCase): len(self.service.index(self.context))) def test_create_and_show_non_existing_image(self): - fixture = self._make_fixture('test image') - num_images = len(self.service.index(self.context)) - + fixture = self._make_fixture(name='test image') image_id = self.service.create(self.context, fixture)['id'] self.assertNotEquals(None, image_id) @@ -428,9 +267,7 @@ class GlanceImageServiceTest(test.TestCase): 'bad image id') def test_create_and_show_non_existing_image_by_name(self): - fixture = self._make_fixture('test image') - num_images = len(self.service.index(self.context)) - + fixture = self._make_fixture(name='test image') image_id = self.service.create(self.context, fixture)['id'] self.assertNotEquals(None, image_id) @@ -440,17 +277,17 @@ class GlanceImageServiceTest(test.TestCase): 'bad image id') def test_index(self): - fixture = self._make_fixture('test image') + fixture = self._make_fixture(name='test image') image_id = self.service.create(self.context, fixture)['id'] image_metas = self.service.index(self.context) - expected = [{'id': 'DONTCARE', 'name': 'test image'}] + expected = [{'id': image_id, 'name': 'test image'}] self.assertDictListMatch(image_metas, expected) def test_index_default_limit(self): fixtures = [] ids = [] for i in range(10): - fixture = self._make_fixture('TestImage %d' % (i)) + fixture = self._make_fixture(name='TestImage %d' % (i)) fixtures.append(fixture) ids.append(self.service.create(self.context, fixture)['id']) @@ -466,7 +303,7 @@ class GlanceImageServiceTest(test.TestCase): fixtures = [] ids = [] for i in range(10): - fixture = self._make_fixture('TestImage %d' % (i)) + fixture = self._make_fixture(name='TestImage %d' % (i)) fixtures.append(fixture) ids.append(self.service.create(self.context, fixture)['id']) @@ -483,18 +320,18 @@ class GlanceImageServiceTest(test.TestCase): fixtures = [] ids = [] for i in range(10): - fixture = self._make_fixture('TestImage %d' % (i)) + fixture = self._make_fixture(name='TestImage %d' % (i)) fixtures.append(fixture) ids.append(self.service.create(self.context, fixture)['id']) - image_metas = self.service.index(self.context, limit=3) - self.assertEquals(len(image_metas), 3) + image_metas = self.service.index(self.context, limit=5) + self.assertEquals(len(image_metas), 5) def test_index_marker_and_limit(self): fixtures = [] ids = [] for i in range(10): - fixture = self._make_fixture('TestImage %d' % (i)) + fixture = self._make_fixture(name='TestImage %d' % (i)) fixtures.append(fixture) ids.append(self.service.create(self.context, fixture)['id']) @@ -502,7 +339,7 @@ class GlanceImageServiceTest(test.TestCase): self.assertEquals(len(image_metas), 1) i = 4 for meta in image_metas: - expected = {'id': 'DONTCARE', + expected = {'id': ids[i], 'name': 'TestImage %d' % (i)} self.assertDictMatch(meta, expected) i = i + 1 @@ -511,7 +348,7 @@ class GlanceImageServiceTest(test.TestCase): fixtures = [] ids = [] for i in range(10): - fixture = self._make_fixture('TestImage %d' % (i)) + fixture = self._make_fixture(name='TestImage %d' % (i)) fixtures.append(fixture) ids.append(self.service.create(self.context, fixture)['id']) @@ -520,11 +357,11 @@ class GlanceImageServiceTest(test.TestCase): i = 2 for meta in image_metas: expected = { - 'id': 'DONTCARE', + 'id': ids[i], 'status': None, - 'is_public': True, + 'is_public': None, 'name': 'TestImage %d' % (i), - 'properties': {'one': 'two'}, + 'properties': {}, 'size': None, 'location': None, 'disk_format': None, @@ -536,8 +373,6 @@ class GlanceImageServiceTest(test.TestCase): 'deleted': None } - print meta - print expected self.assertDictMatch(meta, expected) i = i + 1 @@ -545,31 +380,31 @@ class GlanceImageServiceTest(test.TestCase): fixtures = [] ids = [] for i in range(10): - fixture = self._make_fixture('TestImage %d' % (i)) + fixture = self._make_fixture(name='TestImage %d' % (i)) fixtures.append(fixture) ids.append(self.service.create(self.context, fixture)['id']) - image_metas = self.service.detail(self.context, limit=3) - self.assertEquals(len(image_metas), 3) + image_metas = self.service.detail(self.context, limit=5) + self.assertEquals(len(image_metas), 5) def test_detail_marker_and_limit(self): fixtures = [] ids = [] for i in range(10): - fixture = self._make_fixture('TestImage %d' % (i)) + fixture = self._make_fixture(name='TestImage %d' % (i)) fixtures.append(fixture) ids.append(self.service.create(self.context, fixture)['id']) - image_metas = self.service.detail(self.context, marker=ids[3], limit=3) - self.assertEquals(len(image_metas), 3) + image_metas = self.service.detail(self.context, marker=ids[3], limit=5) + self.assertEquals(len(image_metas), 5) i = 4 for meta in image_metas: expected = { - 'id': 'DONTCARE', + 'id': ids[i], 'status': None, - 'is_public': True, + 'is_public': None, 'name': 'TestImage %d' % (i), - 'properties': {'one': 'two'}, + 'properties': {}, 'size': None, 'location': None, 'disk_format': None, @@ -584,18 +419,17 @@ class GlanceImageServiceTest(test.TestCase): i = i + 1 def test_update(self): - fixture = self._make_fixture('test image') + fixture = self._make_fixture(name='test image') image_id = self.service.create(self.context, fixture)['id'] - fixture['status'] = 'in progress' - + fixture['name'] = 'new image name' self.service.update(self.context, image_id, fixture) new_image_data = self.service.show(self.context, image_id) - self.assertEquals('in progress', new_image_data['status']) + self.assertEquals('new image name', new_image_data['name']) def test_delete(self): - fixture1 = self._make_fixture('test image 1') - fixture2 = self._make_fixture('test image 2') + fixture1 = self._make_fixture(name='test image 1') + fixture2 = self._make_fixture(name='test image 2') fixtures = [fixture1, fixture2] num_images = len(self.service.index(self.context)) @@ -613,3 +447,118 @@ class GlanceImageServiceTest(test.TestCase): num_images = len(self.service.index(self.context)) self.assertEquals(1, num_images) + + def test_show_passes_through_to_client(self): + fixture = self._make_fixture(name='image1', is_public=True) + image_id = self.service.create(self.context, fixture)['id'] + + image_meta = self.service.show(self.context, image_id) + expected = {'id': image_id, 'name': 'image1', 'is_public': True, + 'size': None, 'location': None, 'disk_format': None, + 'container_format': None, 'checksum': None, + 'created_at': None, 'updated_at': None, + 'deleted_at': None, 'deleted': None, 'status': None, + 'properties': {}} + self.assertEqual(image_meta, expected) + + def test_show_raises_when_no_authtoken_in_the_context(self): + fixture = self._make_fixture(name='image1', + is_public=False, + properties={'one': 'two'}) + image_id = self.service.create(self.context, fixture)['id'] + self.context.auth_token = False + self.assertRaises(exception.ImageNotFound, + self.service.show, + self.context, + image_id) + + def test_detail_passes_through_to_client(self): + fixture = self._make_fixture(name='image10', is_public=True) + image_id = self.service.create(self.context, fixture)['id'] + image_metas = self.service.detail(self.context) + expected = [{'id': image_id, 'name': 'image10', 'is_public': True, + 'size': None, 'location': None, 'disk_format': None, + 'container_format': None, 'checksum': None, + 'created_at': None, 'updated_at': None, + 'deleted_at': None, 'deleted': None, 'status': None, + 'properties': {}}] + self.assertEqual(image_metas, expected) + + def test_show_handles_none_datetimes(self): + fixture = self._make_fixture(updated_at=None, deleted_at=None) + image_id = self.service.create(self.context, fixture)['id'] + image_meta = self.service.show(self.context, image_id) + self.assertDateTimesEmpty(image_meta) + + def test_show_handles_blank_datetimes(self): + fixture = self._make_fixture(updated_at='', deleted_at='') + image_id = self.service.create(self.context, fixture)['id'] + image_meta = self.service.show(self.context, image_id) + self.assertDateTimesBlank(image_meta) + + def test_detail_handles_none_datetimes(self): + fixture = self._make_fixture(updated_at=None, deleted_at=None) + self.service.create(self.context, fixture) + image_meta = self.service.detail(self.context)[0] + self.assertDateTimesEmpty(image_meta) + + def test_detail_handles_blank_datetimes(self): + fixture = self._make_fixture(updated_at='', deleted_at='') + self.service.create(self.context, fixture) + image_meta = self.service.detail(self.context)[0] + self.assertDateTimesBlank(image_meta) + + def test_get_handles_none_datetimes(self): + fixture = self._make_fixture(updated_at=None, deleted_at=None) + image_id = self.service.create(self.context, fixture)['id'] + writer = NullWriter() + image_meta = self.service.get(self.context, image_id, writer) + self.assertDateTimesEmpty(image_meta) + + def test_get_handles_blank_datetimes(self): + fixture = self._make_fixture(updated_at='', deleted_at='') + image_id = self.service.create(self.context, fixture)['id'] + writer = NullWriter() + image_meta = self.service.get(self.context, image_id, writer) + self.assertDateTimesBlank(image_meta) + + def test_show_makes_datetimes(self): + fixture = self._make_datetime_fixture() + image_id = self.service.create(self.context, fixture)['id'] + image_meta = self.service.show(self.context, image_id) + self.assertDateTimesFilled(image_meta) + + def test_detail_makes_datetimes(self): + fixture = self._make_datetime_fixture() + self.service.create(self.context, fixture) + image_meta = self.service.detail(self.context)[0] + self.assertDateTimesFilled(image_meta) + + def test_get_makes_datetimes(self): + fixture = self._make_datetime_fixture() + image_id = self.service.create(self.context, fixture)['id'] + writer = NullWriter() + image_meta = self.service.get(self.context, image_id, writer) + self.assertDateTimesFilled(image_meta) + + def test_create_handles_datetimes(self): + fixture = self._make_datetime_fixture() + image_meta = self.service.create(self.context, fixture) + self.assertDateTimesFilled(image_meta) + + def test_create_handles_none_datetimes(self): + fixture = self._make_none_datetime_fixture() + image_meta = self.service.create(self.context, fixture) + self.assertDateTimesEmpty(image_meta) + + def test_update_handles_datetimes(self): + fixture = self._make_datetime_fixture() + image_id = self.service.create(self.context, fixture)['id'] + image_meta = self.service.update(self.context, image_id, {}) + self.assertDateTimesFilled(image_meta) + + def test_update_handles_none_datetimes(self): + fixture = self._make_none_datetime_fixture() + image_id = self.service.create(self.context, fixture)['id'] + image_meta = self.service.update(self.context, image_id, {}) + self.assertDateTimesEmpty(image_meta) -- cgit From 35e0ae794f6cd5fda47c4795da34f9f57f52614f Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 6 Sep 2011 15:16:40 -0400 Subject: further cleanup --- nova/tests/api/openstack/fakes.py | 125 +++------- nova/tests/api/openstack/test_image_metadata.py | 163 +++++------- nova/tests/api/openstack/test_images.py | 313 ++++++++++++------------ nova/tests/glance/stubs.py | 69 ++++++ nova/tests/image/test_glance.py | 269 ++++++-------------- nova/tests/test_xenapi.py | 2 +- 6 files changed, 413 insertions(+), 528 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py index 44681d395..9faeeaa8a 100644 --- a/nova/tests/api/openstack/fakes.py +++ b/nova/tests/api/openstack/fakes.py @@ -42,6 +42,7 @@ import nova.image.fake from nova.image import glance from nova.image import service from nova.tests import fake_flags +from nova.tests.glance import stubs as glance_stubs class Context(object): @@ -83,7 +84,7 @@ def wsgi_app(inner_app10=None, inner_app11=None, fake_auth=True, if fake_auth_context is not None: ctxt = fake_auth_context else: - ctxt = context.RequestContext('fake', 'fake') + ctxt = context.RequestContext('fake', 'fake', auth_token=True) api10 = openstack.FaultWrapper(api_auth.InjectContext(ctxt, limits.RateLimitingMiddleware(inner_app10))) api11 = openstack.FaultWrapper(api_auth.InjectContext(ctxt, @@ -177,6 +178,38 @@ def stub_out_compute_api_backup(stubs): stubs.Set(nova.compute.API, 'backup', backup) +def _make_image_fixtures(): + NOW_GLANCE_FORMAT = "2010-10-11T10:30:22" + + image_id = 123 + base_attrs = {'deleted': False} + + fixtures = [] + + def add_fixture(**kwargs): + kwargs.update(base_attrs) + fixtures.append(kwargs) + + # Public image + add_fixture(id=image_id, name='public image', is_public=True, + status='active', properties={'key1': 'value1'}) + image_id += 1 + + # Snapshot for User 1 + server_ref = 'http://localhost/v1.1/servers/42' + snapshot_properties = {'instance_ref': server_ref, 'user_id': 'fake'} + for status in ('queued', 'saving', 'active', 'killed'): + add_fixture(id=image_id, name='%s snapshot' % status, + is_public=False, status=status, + properties=snapshot_properties) + image_id += 1 + + # Image without a name + add_fixture(id=image_id, is_public=True, status='active', properties={}) + + return fixtures + + def stub_out_glance_add_image(stubs, sent_to_glance): """ We return the metadata sent to glance by modifying the sent_to_glance dict @@ -192,91 +225,11 @@ def stub_out_glance_add_image(stubs, sent_to_glance): stubs.Set(glance_client.Client, 'add_image', fake_add_image) -def stub_out_glance(stubs, initial_fixtures=None): - - class FakeGlanceClient: - - def __init__(self, initial_fixtures): - self.fixtures = initial_fixtures or [] - - def _filter_images(self, filters=None, marker=None, limit=None): - found = True - if marker: - found = False - if limit == 0: - limit = None - - fixtures = [] - count = 0 - for f in self.fixtures: - if limit and count >= limit: - break - if found: - fixtures.append(f) - count = count + 1 - if f['id'] == marker: - found = True - - return fixtures - - def fake_get_images(self, filters=None, marker=None, limit=None): - fixtures = self._filter_images(filters, marker, limit) - return [dict(id=f['id'], name=f['name']) - for f in fixtures] - - def fake_get_images_detailed(self, filters=None, - marker=None, limit=None): - return self._filter_images(filters, marker, limit) - - def fake_get_image_meta(self, image_id): - image = self._find_image(image_id) - if image: - return copy.deepcopy(image) - raise glance_exc.NotFound - - def fake_add_image(self, image_meta, data=None): - image_meta = copy.deepcopy(image_meta) - image_id = ''.join(random.choice(string.letters) - for _ in range(20)) - image_meta['id'] = image_id - self.fixtures.append(image_meta) - return copy.deepcopy(image_meta) - - def fake_update_image(self, image_id, image_meta, data=None): - for attr in ('created_at', 'updated_at', 'deleted_at', 'deleted'): - if attr in image_meta: - del image_meta[attr] - - f = self._find_image(image_id) - if not f: - raise glance_exc.NotFound - - f.update(image_meta) - return copy.deepcopy(f) - - def fake_delete_image(self, image_id): - f = self._find_image(image_id) - if not f: - raise glance_exc.NotFound - - self.fixtures.remove(f) - - def _find_image(self, image_id): - for f in self.fixtures: - if str(f['id']) == str(image_id): - return f - return None - - GlanceClient = glance_client.Client - fake = FakeGlanceClient(initial_fixtures) - - stubs.Set(GlanceClient, 'get_images', fake.fake_get_images) - stubs.Set(GlanceClient, 'get_images_detailed', - fake.fake_get_images_detailed) - stubs.Set(GlanceClient, 'get_image_meta', fake.fake_get_image_meta) - stubs.Set(GlanceClient, 'add_image', fake.fake_add_image) - stubs.Set(GlanceClient, 'update_image', fake.fake_update_image) - stubs.Set(GlanceClient, 'delete_image', fake.fake_delete_image) +def stub_out_glance(stubs): + def fake_get_image_service(): + client = glance_stubs.StubGlanceClient(_make_image_fixtures()) + return nova.image.glance.GlanceImageService(client) + stubs.Set(nova.image, 'get_default_image_service', fake_get_image_service) class FakeToken(object): diff --git a/nova/tests/api/openstack/test_image_metadata.py b/nova/tests/api/openstack/test_image_metadata.py index fe42e35e5..314c3c38e 100644 --- a/nova/tests/api/openstack/test_image_metadata.py +++ b/nova/tests/api/openstack/test_image_metadata.py @@ -23,7 +23,6 @@ from nova import flags from nova.api import openstack from nova import test from nova.tests.api.openstack import fakes -import nova.wsgi FLAGS = flags.FLAGS @@ -31,76 +30,20 @@ FLAGS = flags.FLAGS class ImageMetaDataTest(test.TestCase): - IMAGE_FIXTURES = [ - {'status': 'active', - 'name': 'image1', - 'deleted': False, - 'container_format': None, - 'checksum': None, - 'created_at': '2011-03-22T17:40:15', - 'disk_format': None, - 'updated_at': '2011-03-22T17:40:15', - 'id': '1', - 'location': 'file:///var/lib/glance/images/1', - 'is_public': True, - 'deleted_at': None, - 'properties': { - 'key1': 'value1', - 'key2': 'value2'}, - 'size': 5882349}, - {'status': 'active', - 'name': 'image2', - 'deleted': False, - 'container_format': None, - 'checksum': None, - 'created_at': '2011-03-22T17:40:15', - 'disk_format': None, - 'updated_at': '2011-03-22T17:40:15', - 'id': '2', - 'location': 'file:///var/lib/glance/images/2', - 'is_public': True, - 'deleted_at': None, - 'properties': { - 'key1': 'value1', - 'key2': 'value2'}, - 'size': 5882349}, - {'status': 'active', - 'name': 'image3', - 'deleted': False, - 'container_format': None, - 'checksum': None, - 'created_at': '2011-03-22T17:40:15', - 'disk_format': None, - 'updated_at': '2011-03-22T17:40:15', - 'id': '3', - 'location': 'file:///var/lib/glance/images/2', - 'is_public': True, - 'deleted_at': None, - 'properties': {}, - 'size': 5882349}, - ] - def setUp(self): super(ImageMetaDataTest, self).setUp() - self.flags(image_service='nova.image.glance.GlanceImageService') - # NOTE(dprince) max out properties/metadata in image 3 for testing - img3 = self.IMAGE_FIXTURES[2] - for num in range(FLAGS.quota_metadata_items): - img3['properties']['key%i' % num] = "blah" - fakes.stub_out_glance(self.stubs, self.IMAGE_FIXTURES) + fakes.stub_out_glance(self.stubs) def test_index(self): - req = webob.Request.blank('/v1.1/123/images/1/metadata') + req = webob.Request.blank('/v1.1/123/images/123/metadata') res = req.get_response(fakes.wsgi_app()) res_dict = json.loads(res.body) self.assertEqual(200, res.status_int) - expected = self.IMAGE_FIXTURES[0]['properties'] - self.assertEqual(len(expected), len(res_dict['metadata'])) - for (key, value) in res_dict['metadata'].items(): - self.assertEqual(value, res_dict['metadata'][key]) + expected = {'metadata': {'key1': 'value1'}} + self.assertEqual(res_dict, expected) def test_show(self): - req = webob.Request.blank('/v1.1/fake/images/1/metadata/key1') + req = webob.Request.blank('/v1.1/fake/images/123/metadata/key1') res = req.get_response(fakes.wsgi_app()) res_dict = json.loads(res.body) self.assertEqual(200, res.status_int) @@ -109,32 +52,38 @@ class ImageMetaDataTest(test.TestCase): self.assertEqual('value1', res_dict['meta']['key1']) def test_show_not_found(self): - req = webob.Request.blank('/v1.1/fake/images/1/metadata/key9') + req = webob.Request.blank('/v1.1/fake/images/123/metadata/key9') + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(404, res.status_int) + + def test_show_image_not_found(self): + req = webob.Request.blank('/v1.1/fake/images/100/metadata/key1') res = req.get_response(fakes.wsgi_app()) self.assertEqual(404, res.status_int) def test_create(self): - req = webob.Request.blank('/v1.1/fake/images/2/metadata') + req = webob.Request.blank('/v1.1/fake/images/123/metadata') req.method = 'POST' - req.body = '{"metadata": {"key9": "value9"}}' + req.body = '{"metadata": {"key7": "value7"}}' req.headers["content-type"] = "application/json" res = req.get_response(fakes.wsgi_app()) self.assertEqual(200, res.status_int) actual_output = json.loads(res.body) + expected_output = {'metadata': {'key1': 'value1', 'key7': 'value7'}} + self.assertEqual(expected_output, actual_output) - expected_output = { - 'metadata': { - 'key1': 'value1', - 'key2': 'value2', - 'key9': 'value9', - }, - } + def test_create_image_not_found(self): + req = webob.Request.blank('/v1.1/fake/images/100/metadata') + req.method = 'POST' + req.body = '{"metadata": {"key7": "value7"}}' + req.headers["content-type"] = "application/json" + res = req.get_response(fakes.wsgi_app()) - self.assertEqual(expected_output, actual_output) + self.assertEqual(404, res.status_int) def test_update_all(self): - req = webob.Request.blank('/v1.1/fake/images/1/metadata') + req = webob.Request.blank('/v1.1/fake/images/123/metadata') req.method = 'PUT' req.body = '{"metadata": {"key9": "value9"}}' req.headers["content-type"] = "application/json" @@ -142,17 +91,20 @@ class ImageMetaDataTest(test.TestCase): self.assertEqual(200, res.status_int) actual_output = json.loads(res.body) + expected_output = {'metadata': {'key9': 'value9'}} + self.assertEqual(expected_output, actual_output) - expected_output = { - 'metadata': { - 'key9': 'value9', - }, - } + def test_update_all_image_not_found(self): + req = webob.Request.blank('/v1.1/fake/images/100/metadata') + req.method = 'PUT' + req.body = '{"metadata": {"key9": "value9"}}' + req.headers["content-type"] = "application/json" + res = req.get_response(fakes.wsgi_app()) - self.assertEqual(expected_output, actual_output) + self.assertEqual(404, res.status_int) def test_update_item(self): - req = webob.Request.blank('/v1.1/fake/images/1/metadata/key1') + req = webob.Request.blank('/v1.1/fake/images/123/metadata/key1') req.method = 'PUT' req.body = '{"meta": {"key1": "zz"}}' req.headers["content-type"] = "application/json" @@ -160,15 +112,20 @@ class ImageMetaDataTest(test.TestCase): self.assertEqual(200, res.status_int) actual_output = json.loads(res.body) - expected_output = { - 'meta': { - 'key1': 'zz', - }, - } + expected_output = {'meta': {'key1': 'zz'}} self.assertEqual(actual_output, expected_output) + def test_update_item_image_not_found(self): + req = webob.Request.blank('/v1.1/fake/images/100/metadata/key1') + req.method = 'PUT' + req.body = '{"meta": {"key1": "zz"}}' + req.headers["content-type"] = "application/json" + res = req.get_response(fakes.wsgi_app()) + + self.assertEqual(404, res.status_int) + def test_update_item_bad_body(self): - req = webob.Request.blank('/v1.1/fake/images/1/metadata/key1') + req = webob.Request.blank('/v1.1/fake/images/123/metadata/key1') req.method = 'PUT' req.body = '{"key1": "zz"}' req.headers["content-type"] = "application/json" @@ -176,15 +133,18 @@ class ImageMetaDataTest(test.TestCase): self.assertEqual(400, res.status_int) def test_update_item_too_many_keys(self): - req = webob.Request.blank('/v1.1/fake/images/1/metadata/key1') + req = webob.Request.blank('/v1.1/fake/images/123/metadata/key1') req.method = 'PUT' - req.body = '{"meta": {"key1": "value1", "key2": "value2"}}' + overload = {} + for num in range(FLAGS.quota_metadata_items + 1): + overload['key%s' % num] = 'value%s' % num + req.body = json.dumps({'meta': overload}) req.headers["content-type"] = "application/json" res = req.get_response(fakes.wsgi_app()) self.assertEqual(400, res.status_int) def test_update_item_body_uri_mismatch(self): - req = webob.Request.blank('/v1.1/fake/images/1/metadata/bad') + req = webob.Request.blank('/v1.1/fake/images/123/metadata/bad') req.method = 'PUT' req.body = '{"meta": {"key1": "value1"}}' req.headers["content-type"] = "application/json" @@ -192,7 +152,7 @@ class ImageMetaDataTest(test.TestCase): self.assertEqual(400, res.status_int) def test_update_item_xml(self): - req = webob.Request.blank('/v1.1/fake/images/1/metadata/key1') + req = webob.Request.blank('/v1.1/fake/images/123/metadata/key1') req.method = 'PUT' req.body = 'five' req.headers["content-type"] = "application/xml" @@ -200,22 +160,24 @@ class ImageMetaDataTest(test.TestCase): self.assertEqual(200, res.status_int) actual_output = json.loads(res.body) - expected_output = { - 'meta': { - 'key1': 'five', - }, - } + expected_output = {'meta': {'key1': 'five'}} self.assertEqual(actual_output, expected_output) def test_delete(self): - req = webob.Request.blank('/v1.1/fake/images/2/metadata/key1') + req = webob.Request.blank('/v1.1/fake/images/123/metadata/key1') req.method = 'DELETE' res = req.get_response(fakes.wsgi_app()) self.assertEqual(204, res.status_int) self.assertEqual('', res.body) def test_delete_not_found(self): - req = webob.Request.blank('/v1.1/fake/images/2/metadata/blah') + req = webob.Request.blank('/v1.1/fake/images/123/metadata/blah') + req.method = 'DELETE' + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(404, res.status_int) + + def test_delete_image_not_found(self): + req = webob.Request.blank('/v1.1/fake/images/100/metadata/key1') req.method = 'DELETE' res = req.get_response(fakes.wsgi_app()) self.assertEqual(404, res.status_int) @@ -225,7 +187,7 @@ class ImageMetaDataTest(test.TestCase): for num in range(FLAGS.quota_metadata_items + 1): data['metadata']['key%i' % num] = "blah" json_string = str(data).replace("\'", "\"") - req = webob.Request.blank('/v1.1/fake/images/2/metadata') + req = webob.Request.blank('/v1.1/fake/images/123/metadata') req.method = 'POST' req.body = json_string req.headers["content-type"] = "application/json" @@ -233,7 +195,8 @@ class ImageMetaDataTest(test.TestCase): self.assertEqual(413, res.status_int) def test_too_many_metadata_items_on_put(self): - req = webob.Request.blank('/v1.1/fake/images/3/metadata/blah') + FLAGS.quota_metadata_items = 1 + req = webob.Request.blank('/v1.1/fake/images/123/metadata/blah') req.method = 'PUT' req.body = '{"meta": {"blah": "blah"}}' req.headers["content-type"] = "application/json" diff --git a/nova/tests/api/openstack/test_images.py b/nova/tests/api/openstack/test_images.py index 942bab5c7..298b7d831 100644 --- a/nova/tests/api/openstack/test_images.py +++ b/nova/tests/api/openstack/test_images.py @@ -29,31 +29,30 @@ import stubout import webob from nova import context -from nova import test import nova.api.openstack from nova.api.openstack import images +from nova import test from nova.tests.api.openstack import fakes +NOW_API_FORMAT = "2010-10-11T10:30:22Z" + + class ImagesTest(test.TestCase): """ Test of the OpenStack API /images application controller w/Glance. """ - NOW_GLANCE_FORMAT = "2010-10-11T10:30:22" - NOW_API_FORMAT = "2010-10-11T10:30:22Z" def setUp(self): """Run before each test.""" super(ImagesTest, self).setUp() - self.flags(image_service='nova.image.glance.GlanceImageService') self.stubs = stubout.StubOutForTesting() fakes.stub_out_networking(self.stubs) fakes.stub_out_rate_limiting(self.stubs) fakes.stub_out_key_pair_funcs(self.stubs) - self.fixtures = self._make_image_fixtures() - fakes.stub_out_glance(self.stubs, initial_fixtures=self.fixtures) fakes.stub_out_compute_api_snapshot(self.stubs) fakes.stub_out_compute_api_backup(self.stubs) + fakes.stub_out_glance(self.stubs) def tearDown(self): """Run after each test.""" @@ -63,36 +62,30 @@ class ImagesTest(test.TestCase): def _get_fake_context(self): class Context(object): project_id = 'fake' + auth_token = True return Context() - def _applicable_fixture(self, fixture, user_id): - """Determine if this fixture is applicable for given user id.""" - is_public = fixture["is_public"] - try: - uid = fixture["properties"]["user_id"] - except KeyError: - uid = None - return uid == user_id or is_public - def test_get_image_index(self): request = webob.Request.blank('/v1.0/images') - response = request.get_response(fakes.wsgi_app()) + app = fakes.wsgi_app(fake_auth_context=self._get_fake_context()) + response = request.get_response(app) response_dict = json.loads(response.body) response_list = response_dict["images"] - expected = [{'id': 123, 'name': 'public image'}, - {'id': 124, 'name': 'queued snapshot'}, - {'id': 125, 'name': 'saving snapshot'}, - {'id': 126, 'name': 'active snapshot'}, - {'id': 127, 'name': 'killed snapshot'}, - {'id': 129, 'name': None}] + expected = [{'id': '123', 'name': 'public image'}, + {'id': '124', 'name': 'queued snapshot'}, + {'id': '125', 'name': 'saving snapshot'}, + {'id': '126', 'name': 'active snapshot'}, + {'id': '127', 'name': 'killed snapshot'}, + {'id': '128', 'name': None}] self.assertDictListMatch(response_list, expected) def test_get_image(self): request = webob.Request.blank('/v1.0/images/123') - response = request.get_response(fakes.wsgi_app()) + app = fakes.wsgi_app(fake_auth_context=self._get_fake_context()) + response = request.get_response(app) self.assertEqual(200, response.status_int) @@ -100,20 +93,21 @@ class ImagesTest(test.TestCase): expected_image = { "image": { - "id": 123, + "id": "123", "name": "public image", - "updated": self.NOW_API_FORMAT, - "created": self.NOW_API_FORMAT, + "updated": NOW_API_FORMAT, + "created": NOW_API_FORMAT, "status": "ACTIVE", "progress": 100, }, } - self.assertEqual(expected_image, actual_image) + self.assertDictMatch(expected_image, actual_image) def test_get_image_v1_1(self): request = webob.Request.blank('/v1.1/fake/images/124') - response = request.get_response(fakes.wsgi_app()) + app = fakes.wsgi_app(fake_auth_context=self._get_fake_context()) + response = request.get_response(app) actual_image = json.loads(response.body) @@ -124,10 +118,10 @@ class ImagesTest(test.TestCase): expected_image = { "image": { - "id": 124, + "id": "124", "name": "queued snapshot", - "updated": self.NOW_API_FORMAT, - "created": self.NOW_API_FORMAT, + "updated": NOW_API_FORMAT, + "created": NOW_API_FORMAT, "status": "QUEUED", "progress": 0, 'server': { @@ -161,11 +155,12 @@ class ImagesTest(test.TestCase): def test_get_image_xml(self): request = webob.Request.blank('/v1.0/images/123') request.accept = "application/xml" - response = request.get_response(fakes.wsgi_app()) + app = fakes.wsgi_app(fake_auth_context=self._get_fake_context()) + response = request.get_response(app) actual_image = minidom.parseString(response.body.replace(" ", "")) - expected_now = self.NOW_API_FORMAT + expected_now = NOW_API_FORMAT expected_image = minidom.parseString(""" Date: Tue, 6 Sep 2011 16:28:34 -0400 Subject: reverting xenapi change --- nova/tests/api/openstack/fakes.py | 1 - nova/tests/test_xenapi.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py index 9faeeaa8a..c1b5f884c 100644 --- a/nova/tests/api/openstack/fakes.py +++ b/nova/tests/api/openstack/fakes.py @@ -40,7 +40,6 @@ from nova.api.openstack import limits from nova.auth.manager import User, Project import nova.image.fake from nova.image import glance -from nova.image import service from nova.tests import fake_flags from nova.tests.glance import stubs as glance_stubs diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index 27a8a979d..45dad3516 100644 --- a/nova/tests/test_xenapi.py +++ b/nova/tests/test_xenapi.py @@ -745,7 +745,7 @@ class XenAPIMigrateInstance(test.TestCase): fake_utils.stub_out_utils_execute(self.stubs) stubs.stub_out_migration_methods(self.stubs) stubs.stubout_get_this_vm_uuid(self.stubs) - #glance_stubs.stubout_glance_client(self.stubs) + glance_stubs.stubout_glance_client(self.stubs) def test_migrate_disk_and_power_off(self): instance = db.instance_create(self.context, self.values) -- cgit From b890b992f3013a1959e3c3cdf1f149cacf4e569b Mon Sep 17 00:00:00 2001 From: Naveed Massjouni Date: Thu, 8 Sep 2011 21:30:21 -0400 Subject: Fixing security groups stuff --- .../api/openstack/contrib/test_createserverext.py | 6 ++- nova/tests/api/openstack/test_versions.py | 43 +++++++--------------- 2 files changed, 19 insertions(+), 30 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/contrib/test_createserverext.py b/nova/tests/api/openstack/contrib/test_createserverext.py index 078b72d67..03c7d1ec5 100644 --- a/nova/tests/api/openstack/contrib/test_createserverext.py +++ b/nova/tests/api/openstack/contrib/test_createserverext.py @@ -49,9 +49,13 @@ INSTANCE = { "id": 1, "display_name": "test_server", "uuid": FAKE_UUID, + "user_id": 'fake_user_id', + "tenant_id": 'fake_tenant_id', "created_at": datetime.datetime(2010, 10, 10, 12, 0, 0), "updated_at": datetime.datetime(2010, 11, 11, 11, 0, 0), - "security_groups": [{"id": 1, "name": "test"}] + "security_groups": [{"id": 1, "name": "test"}], + "image_ref": 'http://foo.com/123', + "instance_type": {"flavorid": '124'}, } diff --git a/nova/tests/api/openstack/test_versions.py b/nova/tests/api/openstack/test_versions.py index 8b60db71e..686752509 100644 --- a/nova/tests/api/openstack/test_versions.py +++ b/nova/tests/api/openstack/test_versions.py @@ -23,10 +23,11 @@ from lxml import etree from nova import context from nova import test -from nova.tests.api.openstack import fakes from nova.api.openstack import versions from nova.api.openstack import views from nova.api.openstack import wsgi +from nova.tests.api.openstack import common +from nova.tests.api.openstack import fakes NS = { 'atom': 'http://www.w3.org/2005/Atom', @@ -243,12 +244,12 @@ class VersionsTest(test.TestCase): self.assertTrue(version.xpath('/ns:version', namespaces=NS)) media_types = version.xpath('ns:media-types/ns:media-type', namespaces=NS) - self.assertTrue(_compare_media_types(media_types, + self.assertTrue(common.compare_media_types(media_types, expected['media-types'])) for key in ['id', 'status', 'updated']: self.assertEqual(version.get(key), expected[key]) links = version.xpath('atom:link', namespaces=NS) - self.assertTrue(_compare_links(links, + self.assertTrue(common.compare_links(links, [{'rel': 'self', 'href': 'http://localhost/v1.0/'}] + expected['links'])) @@ -264,12 +265,12 @@ class VersionsTest(test.TestCase): self.assertTrue(version.xpath('/ns:version', namespaces=NS)) media_types = version.xpath('ns:media-types/ns:media-type', namespaces=NS) - self.assertTrue(_compare_media_types(media_types, + self.assertTrue(common.compare_media_types(media_types, expected['media-types'])) for key in ['id', 'status', 'updated']: self.assertEqual(version.get(key), expected[key]) links = version.xpath('atom:link', namespaces=NS) - self.assertTrue(_compare_links(links, + self.assertTrue(common.compare_links(links, [{'rel': 'self', 'href': 'http://localhost/v1.1/'}] + expected['links'])) @@ -291,7 +292,7 @@ class VersionsTest(test.TestCase): for key in ['id', 'status', 'updated']: self.assertEqual(version.get(key), expected[key]) (link,) = version.xpath('atom:link', namespaces=NS) - self.assertTrue(_compare_links(link, + self.assertTrue(common.compare_links(link, [{'rel': 'self', 'href': 'http://localhost/%s/' % v}])) def test_get_version_1_0_detail_atom(self): @@ -496,10 +497,10 @@ class VersionsTest(test.TestCase): self.assertEqual(version.get('status'), 'CURRENT') media_types = version.xpath('ns:media-types/ns:media-type', namespaces=NS) - self.assertTrue(_compare_media_types(media_types, + self.assertTrue(common.compare_media_types(media_types, VERSIONS['v1.1']['media-types'])) links = version.xpath('atom:link', namespaces=NS) - self.assertTrue(_compare_links(links, + self.assertTrue(common.compare_links(links, [{'rel': 'self', 'href': 'http://localhost/v1.1/images/1'}])) version = versions[1] @@ -507,10 +508,10 @@ class VersionsTest(test.TestCase): self.assertEqual(version.get('status'), 'DEPRECATED') media_types = version.xpath('ns:media-types/ns:media-type', namespaces=NS) - self.assertTrue(_compare_media_types(media_types, + self.assertTrue(common.compare_media_types(media_types, VERSIONS['v1.0']['media-types'])) links = version.xpath('atom:link', namespaces=NS) - self.assertTrue(_compare_links(links, + self.assertTrue(common.compare_links(links, [{'rel': 'self', 'href': 'http://localhost/v1.0/images/1'}])) def test_multi_choice_server_atom(self): @@ -654,7 +655,7 @@ class VersionsSerializerTests(test.TestCase): versions_data['versions'][0]['status']) (link,) = version.xpath('atom:link', namespaces=NS) - self.assertTrue(_compare_links(link, [{ + self.assertTrue(common.compare_links(link, [{ 'rel': 'self', 'href': 'http://test/2.7.1', 'type': 'application/atom+xml'}])) @@ -693,11 +694,11 @@ class VersionsSerializerTests(test.TestCase): media_types = version.xpath('ns:media-types/ns:media-type', namespaces=NS) - self.assertTrue(_compare_media_types(media_types, + self.assertTrue(common.compare_media_types(media_types, versions_data['choices'][0]['media-types'])) (link,) = version.xpath('atom:link', namespaces=NS) - self.assertTrue(_compare_links(link, + self.assertTrue(common.compare_links(link, versions_data['choices'][0]['links'])) def test_version_detail_xml_serializer(self): @@ -882,19 +883,3 @@ class VersionsSerializerTests(test.TestCase): 'servers/api/v1.1/application.wadl', }, ]) - - -def _compare_links(actual, expected): - return _compare_tree_to_dict(actual, expected, ('rel', 'href', 'type')) - - -def _compare_media_types(actual, expected): - return _compare_tree_to_dict(actual, expected, ('base', 'type')) - - -def _compare_tree_to_dict(actual, expected, keys): - for elem, data in zip(actual, expected): - for key in keys: - if elem.get(key) != data.get(key): - return False - return True -- cgit From 13ee200d8265175922b5747f9e00fc31db4803fd Mon Sep 17 00:00:00 2001 From: Naveed Massjouni Date: Thu, 8 Sep 2011 21:37:40 -0400 Subject: pep 8 --- nova/tests/api/openstack/test_servers.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index c3203eb43..9d0f9c4f7 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -496,7 +496,8 @@ class ServersTest(test.TestCase): self.assertEqual(image.get('id'), str(expected['image']['id'])) links = root.xpath('ns:image/atom:link', namespaces=XPATH_NS) - self.assertTrue(common.compare_links(links, expected['image']['links'])) + self.assertTrue(common.compare_links(links, + expected['image']['links'])) (flavor,) = root.xpath('ns:flavor', namespaces=XPATH_NS) self.assertEqual(flavor.get('id'), str(expected['flavor']['id'])) @@ -3663,7 +3664,7 @@ class TestGetKernelRamdiskFromImage(test.TestCase): self.assertRaises(exception.NotFound, self._get_k_r, image_meta) def test_ami_no_ramdisk(self): - """If an ami is missing a ramdisk, return kernel ID and None for + """If an ami is missing a ramdisk, return kernel ID and None for ramdisk ID """ image_meta = {'id': 1, 'status': 'active', 'container_format': 'ami', -- cgit From c890890c7ccbc7df1060d59747089b5e39c5510a Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Sat, 10 Sep 2011 17:11:21 +0900 Subject: api/ec2: make get_metadata() return correct mappings The entries corresponding to volumes are in the form of ebs': --- nova/tests/test_cloud.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'nova/tests') diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index 7fe353b3d..7bdae0552 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -1540,7 +1540,9 @@ class CloudTestCase(test.TestCase): 'ephemeral0': '/dev/sdb', 'swap': '/dev/sdc', 'ephemeral1': '/dev/sdd', - 'ephemeral2': '/dev/sd3'} + 'ephemeral2': '/dev/sd3', + 'ebs0': '/dev/sdh', + 'ebs1': '/dev/sdi'} self.assertEqual(self.cloud._format_instance_mapping(ctxt, instance_ref0), -- cgit From f40955d419c886be29213f73f5ffdf2f38e00057 Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Mon, 12 Sep 2011 08:00:30 -0700 Subject: add test for method sig --- nova/tests/test_libvirt.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'nova/tests') diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index 93967ceec..d776a386b 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -16,6 +16,7 @@ import copy import eventlet +import inspect import mox import os import re @@ -35,6 +36,7 @@ from nova import utils from nova.api.ec2 import cloud from nova.compute import power_state from nova.compute import vm_states +from nova.virt import driver from nova.virt.libvirt import connection from nova.virt.libvirt import firewall from nova.tests import fake_network @@ -840,6 +842,50 @@ class LibvirtConnTestCase(test.TestCase): _assert_volume_in_mapping('sdg', False) _assert_volume_in_mapping('sdh1', False) + def test_reboot_signature(self): + """Test that libvirt driver method sig matches interface""" + def fake_reboot_with_correct_sig(ignore, instance, + network_info, reboot_type): + pass + + def fake_destroy(instance, network_info, cleanup=False): + pass + + def fake_plug_vifs(instance, network_info): + pass + + def fake_create_new_domain(xml): + return + + def fake_none(self, instance): + return + + instance = db.instance_create(self.context, self.test_instance) + network_info = _fake_network_info(self.stubs, 1) + + self.mox.StubOutWithMock(connection.LibvirtConnection, '_conn') + connection.LibvirtConnection._conn.lookupByName = self.fake_lookup + + conn = connection.LibvirtConnection(False) + self.stubs.Set(conn, 'destroy', fake_destroy) + self.stubs.Set(conn, 'plug_vifs', fake_plug_vifs) + self.stubs.Set(conn.firewall_driver, + 'setup_basic_filtering', + fake_none) + self.stubs.Set(conn.firewall_driver, + 'prepare_instance_filter', + fake_none) + self.stubs.Set(conn, '_create_new_domain', fake_create_new_domain) + self.stubs.Set(conn.firewall_driver, + 'apply_instance_filter', + fake_none) + + args = [instance, network_info, 'SOFT'] + conn.reboot(*args) + + compute_driver = driver.ComputeDriver() + self.assertRaises(NotImplementedError, compute_driver.reboot, *args) + class NWFilterFakes: def __init__(self): -- cgit From 4cbfc60b225d0386b6719e49fc9797fd72dc219b Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Mon, 12 Sep 2011 09:15:31 -0700 Subject: remove unused dep --- nova/tests/test_libvirt.py | 1 - 1 file changed, 1 deletion(-) (limited to 'nova/tests') diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index d776a386b..5346e089b 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -16,7 +16,6 @@ import copy import eventlet -import inspect import mox import os import re -- cgit From 17afc6e53f5d53ea80fd747d6ce059c11980c817 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Mon, 12 Sep 2011 18:17:32 -0400 Subject: relocating ec2 tests --- nova/tests/api/ec2/public_key/dummy.fingerprint | 1 + nova/tests/api/ec2/public_key/dummy.pub | 1 + nova/tests/api/ec2/test_cloud.py | 1623 +++++++++++++++++++++++ nova/tests/public_key/dummy.fingerprint | 1 - nova/tests/public_key/dummy.pub | 1 - nova/tests/test_cloud.py | 1623 ----------------------- 6 files changed, 1625 insertions(+), 1625 deletions(-) create mode 100644 nova/tests/api/ec2/public_key/dummy.fingerprint create mode 100644 nova/tests/api/ec2/public_key/dummy.pub create mode 100644 nova/tests/api/ec2/test_cloud.py delete mode 100644 nova/tests/public_key/dummy.fingerprint delete mode 100644 nova/tests/public_key/dummy.pub delete mode 100644 nova/tests/test_cloud.py (limited to 'nova/tests') diff --git a/nova/tests/api/ec2/public_key/dummy.fingerprint b/nova/tests/api/ec2/public_key/dummy.fingerprint new file mode 100644 index 000000000..715bca27a --- /dev/null +++ b/nova/tests/api/ec2/public_key/dummy.fingerprint @@ -0,0 +1 @@ +1c:87:d1:d9:32:fd:62:3c:78:2b:c0:ad:c0:15:88:df diff --git a/nova/tests/api/ec2/public_key/dummy.pub b/nova/tests/api/ec2/public_key/dummy.pub new file mode 100644 index 000000000..d4cf2bc0d --- /dev/null +++ b/nova/tests/api/ec2/public_key/dummy.pub @@ -0,0 +1 @@ +ssh-dss AAAAB3NzaC1kc3MAAACBAMGJlY9XEIm2X234pdO5yFWMp2JuOQx8U0E815IVXhmKxYCBK9ZakgZOIQmPbXoGYyV+mziDPp6HJ0wKYLQxkwLEFr51fAZjWQvRss0SinURRuLkockDfGFtD4pYJthekr/rlqMKlBSDUSpGq8jUWW60UJ18FGooFpxR7ESqQRx/AAAAFQC96LRglaUeeP+E8U/yblEJocuiWwAAAIA3XiMR8Skiz/0aBm5K50SeQznQuMJTyzt9S9uaz5QZWiFu69hOyGSFGw8fqgxEkXFJIuHobQQpGYQubLW0NdaYRqyE/Vud3JUJUb8Texld6dz8vGemyB5d1YvtSeHIo8/BGv2msOqR3u5AZTaGCBD9DhpSGOKHEdNjTtvpPd8S8gAAAIBociGZ5jf09iHLVENhyXujJbxfGRPsyNTyARJfCOGl0oFV6hEzcQyw8U/ePwjgvjc2UizMWLl8tsb2FXKHRdc2v+ND3Us+XqKQ33X3ADP4FZ/+Oj213gMyhCmvFTP0u5FmHog9My4CB7YcIWRuUR42WlhQ2IfPvKwUoTk3R+T6Og== www-data@mk diff --git a/nova/tests/api/ec2/test_cloud.py b/nova/tests/api/ec2/test_cloud.py new file mode 100644 index 000000000..7fe353b3d --- /dev/null +++ b/nova/tests/api/ec2/test_cloud.py @@ -0,0 +1,1623 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# 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. +import mox + +import functools + +from base64 import b64decode +from M2Crypto import BIO +from M2Crypto import RSA +import os + +from eventlet import greenthread + +from nova import context +from nova import crypto +from nova import db +from nova import exception +from nova import flags +from nova import log as logging +from nova import network +from nova import rpc +from nova import test +from nova import utils +from nova.api.ec2 import cloud +from nova.api.ec2 import ec2utils +from nova.compute import vm_states +from nova.image import fake + + +FLAGS = flags.FLAGS +LOG = logging.getLogger('nova.tests.cloud') + + +class CloudTestCase(test.TestCase): + def setUp(self): + super(CloudTestCase, self).setUp() + self.flags(connection_type='fake', + stub_network=True) + + # set up our cloud + self.cloud = cloud.CloudController() + + # set up services + self.compute = self.start_service('compute') + self.scheduter = self.start_service('scheduler') + self.network = self.start_service('network') + self.volume = self.start_service('volume') + self.image_service = utils.import_object(FLAGS.image_service) + + self.user_id = 'fake' + self.project_id = 'fake' + self.context = context.RequestContext(self.user_id, + self.project_id, + True) + + def fake_show(meh, context, id): + return {'id': 1, 'container_format': 'ami', + 'properties': {'kernel_id': 1, 'ramdisk_id': 1, + 'type': 'machine', 'image_state': 'available'}} + + self.stubs.Set(fake._FakeImageService, 'show', fake_show) + self.stubs.Set(fake._FakeImageService, 'show_by_name', fake_show) + + # NOTE(vish): set up a manual wait so rpc.cast has a chance to finish + rpc_cast = rpc.cast + + def finish_cast(*args, **kwargs): + rpc_cast(*args, **kwargs) + greenthread.sleep(0.2) + + self.stubs.Set(rpc, 'cast', finish_cast) + + def _create_key(self, name): + # NOTE(vish): create depends on pool, so just call helper directly + return cloud._gen_key(self.context, self.context.user_id, name) + + def test_describe_regions(self): + """Makes sure describe regions runs without raising an exception""" + result = self.cloud.describe_regions(self.context) + self.assertEqual(len(result['regionInfo']), 1) + self.flags(region_list=["one=test_host1", "two=test_host2"]) + result = self.cloud.describe_regions(self.context) + self.assertEqual(len(result['regionInfo']), 2) + + def test_describe_addresses(self): + """Makes sure describe addresses runs without raising an exception""" + address = "10.10.10.10" + db.floating_ip_create(self.context, + {'address': address, + 'host': self.network.host}) + self.cloud.allocate_address(self.context) + self.cloud.describe_addresses(self.context) + self.cloud.release_address(self.context, + public_ip=address) + db.floating_ip_destroy(self.context, address) + + def test_allocate_address(self): + address = "10.10.10.10" + allocate = self.cloud.allocate_address + db.floating_ip_create(self.context, + {'address': address, + 'host': self.network.host}) + self.assertEqual(allocate(self.context)['publicIp'], address) + db.floating_ip_destroy(self.context, address) + self.assertRaises(exception.NoMoreFloatingIps, + allocate, + self.context) + + def test_release_address(self): + address = "10.10.10.10" + allocate = self.cloud.allocate_address + db.floating_ip_create(self.context, + {'address': address, + 'host': self.network.host}) + result = self.cloud.release_address(self.context, address) + self.assertEqual(result['releaseResponse'], ['Address released.']) + + def test_release_address_still_associated(self): + address = "10.10.10.10" + fixed_ip = {'instance': {'id': 1}} + floating_ip = {'id': 0, + 'address': address, + 'fixed_ip_id': 0, + 'fixed_ip': fixed_ip, + 'project_id': None, + 'auto_assigned': False} + network_api = network.api.API() + self.mox.StubOutWithMock(network_api.db, 'floating_ip_get_by_address') + network_api.db.floating_ip_get_by_address(mox.IgnoreArg(), + mox.IgnoreArg()).AndReturn(floating_ip) + self.mox.ReplayAll() + release = self.cloud.release_address + # ApiError: Floating ip is in use. Disassociate it before releasing. + self.assertRaises(exception.ApiError, release, self.context, address) + + def test_associate_disassociate_address(self): + """Verifies associate runs cleanly without raising an exception""" + address = "10.10.10.10" + db.floating_ip_create(self.context, {'address': address}) + self.cloud.allocate_address(self.context) + # TODO(jkoelker) Probably need to query for instance_type_id and + # make sure we get a valid one + inst = db.instance_create(self.context, {'host': self.compute.host, + 'instance_type_id': 1}) + networks = db.network_get_all(self.context) + for network in networks: + db.network_update(self.context, network['id'], + {'host': self.network.host}) + project_id = self.context.project_id + type_id = inst['instance_type_id'] + ips = self.network.allocate_for_instance(self.context, + instance_id=inst['id'], + host=inst['host'], + vpn=None, + instance_type_id=type_id, + project_id=project_id) + # TODO(jkoelker) Make this mas bueno + self.assertTrue(ips) + self.assertTrue('ips' in ips[0][1]) + self.assertTrue(ips[0][1]['ips']) + self.assertTrue('ip' in ips[0][1]['ips'][0]) + + fixed = ips[0][1]['ips'][0]['ip'] + + ec2_id = ec2utils.id_to_ec2_id(inst['id']) + self.cloud.associate_address(self.context, + instance_id=ec2_id, + public_ip=address) + self.cloud.disassociate_address(self.context, + public_ip=address) + self.cloud.release_address(self.context, + public_ip=address) + self.network.deallocate_fixed_ip(self.context, fixed) + db.instance_destroy(self.context, inst['id']) + db.floating_ip_destroy(self.context, address) + + def test_describe_security_groups(self): + """Makes sure describe_security_groups works and filters results.""" + sec = db.security_group_create(self.context, + {'project_id': self.context.project_id, + 'name': 'test'}) + result = self.cloud.describe_security_groups(self.context) + # NOTE(vish): should have the default group as well + self.assertEqual(len(result['securityGroupInfo']), 2) + result = self.cloud.describe_security_groups(self.context, + group_name=[sec['name']]) + self.assertEqual(len(result['securityGroupInfo']), 1) + self.assertEqual( + result['securityGroupInfo'][0]['groupName'], + sec['name']) + db.security_group_destroy(self.context, sec['id']) + + def test_describe_security_groups_by_id(self): + sec = db.security_group_create(self.context, + {'project_id': self.context.project_id, + 'name': 'test'}) + result = self.cloud.describe_security_groups(self.context, + group_id=[sec['id']]) + self.assertEqual(len(result['securityGroupInfo']), 1) + self.assertEqual( + result['securityGroupInfo'][0]['groupName'], + sec['name']) + default = db.security_group_get_by_name(self.context, + self.context.project_id, + 'default') + result = self.cloud.describe_security_groups(self.context, + group_id=[default['id']]) + self.assertEqual(len(result['securityGroupInfo']), 1) + self.assertEqual( + result['securityGroupInfo'][0]['groupName'], + 'default') + db.security_group_destroy(self.context, sec['id']) + + def test_create_delete_security_group(self): + descript = 'test description' + create = self.cloud.create_security_group + result = create(self.context, 'testgrp', descript) + group_descript = result['securityGroupSet'][0]['groupDescription'] + self.assertEqual(descript, group_descript) + delete = self.cloud.delete_security_group + self.assertTrue(delete(self.context, 'testgrp')) + + def test_delete_security_group_by_id(self): + sec = db.security_group_create(self.context, + {'project_id': self.context.project_id, + 'name': 'test'}) + delete = self.cloud.delete_security_group + self.assertTrue(delete(self.context, group_id=sec['id'])) + + def test_delete_security_group_with_bad_name(self): + delete = self.cloud.delete_security_group + notfound = exception.SecurityGroupNotFound + self.assertRaises(notfound, delete, self.context, 'badname') + + def test_delete_security_group_with_bad_group_id(self): + delete = self.cloud.delete_security_group + notfound = exception.SecurityGroupNotFound + self.assertRaises(notfound, delete, self.context, group_id=999) + + def test_delete_security_group_no_params(self): + delete = self.cloud.delete_security_group + self.assertRaises(exception.ApiError, delete, self.context) + + def test_authorize_security_group_ingress(self): + kwargs = {'project_id': self.context.project_id, 'name': 'test'} + sec = db.security_group_create(self.context, kwargs) + authz = self.cloud.authorize_security_group_ingress + kwargs = {'to_port': '999', 'from_port': '999', 'ip_protocol': 'tcp'} + self.assertTrue(authz(self.context, group_name=sec['name'], **kwargs)) + + def test_authorize_security_group_ingress_ip_permissions_ip_ranges(self): + kwargs = {'project_id': self.context.project_id, 'name': 'test'} + sec = db.security_group_create(self.context, kwargs) + authz = self.cloud.authorize_security_group_ingress + kwargs = {'ip_permissions': [{'to_port': 81, 'from_port': 81, + 'ip_ranges': + {'1': {'cidr_ip': u'0.0.0.0/0'}, + '2': {'cidr_ip': u'10.10.10.10/32'}}, + 'ip_protocol': u'tcp'}]} + self.assertTrue(authz(self.context, group_name=sec['name'], **kwargs)) + + def test_authorize_security_group_fail_missing_source_group(self): + kwargs = {'project_id': self.context.project_id, 'name': 'test'} + sec = db.security_group_create(self.context, kwargs) + authz = self.cloud.authorize_security_group_ingress + kwargs = {'ip_permissions': [{'to_port': 81, 'from_port': 81, + 'ip_ranges':{'1': {'cidr_ip': u'0.0.0.0/0'}, + '2': {'cidr_ip': u'10.10.10.10/32'}}, + 'groups': {'1': {'user_id': u'someuser', + 'group_name': u'somegroup1'}}, + 'ip_protocol': u'tcp'}]} + self.assertRaises(exception.SecurityGroupNotFound, authz, + self.context, group_name=sec['name'], **kwargs) + + def test_authorize_security_group_ingress_ip_permissions_groups(self): + kwargs = {'project_id': self.context.project_id, 'name': 'test'} + sec = db.security_group_create(self.context, + {'project_id': 'someuser', + 'name': 'somegroup1'}) + sec = db.security_group_create(self.context, + {'project_id': 'someuser', + 'name': 'othergroup2'}) + sec = db.security_group_create(self.context, kwargs) + authz = self.cloud.authorize_security_group_ingress + kwargs = {'ip_permissions': [{'to_port': 81, 'from_port': 81, + 'groups': {'1': {'user_id': u'someuser', + 'group_name': u'somegroup1'}, + '2': {'user_id': u'someuser', + 'group_name': u'othergroup2'}}, + 'ip_protocol': u'tcp'}]} + self.assertTrue(authz(self.context, group_name=sec['name'], **kwargs)) + + def test_revoke_security_group_ingress(self): + kwargs = {'project_id': self.context.project_id, 'name': 'test'} + sec = db.security_group_create(self.context, kwargs) + authz = self.cloud.authorize_security_group_ingress + kwargs = {'to_port': '999', 'from_port': '999', 'ip_protocol': 'tcp'} + authz(self.context, group_id=sec['id'], **kwargs) + revoke = self.cloud.revoke_security_group_ingress + self.assertTrue(revoke(self.context, group_name=sec['name'], **kwargs)) + + def test_authorize_revoke_security_group_ingress_by_id(self): + sec = db.security_group_create(self.context, + {'project_id': self.context.project_id, + 'name': 'test'}) + authz = self.cloud.authorize_security_group_ingress + kwargs = {'to_port': '999', 'from_port': '999', 'ip_protocol': 'tcp'} + authz(self.context, group_id=sec['id'], **kwargs) + revoke = self.cloud.revoke_security_group_ingress + self.assertTrue(revoke(self.context, group_id=sec['id'], **kwargs)) + + def test_authorize_security_group_ingress_missing_protocol_params(self): + sec = db.security_group_create(self.context, + {'project_id': self.context.project_id, + 'name': 'test'}) + authz = self.cloud.authorize_security_group_ingress + self.assertRaises(exception.ApiError, authz, self.context, 'test') + + def test_authorize_security_group_ingress_missing_group_name_or_id(self): + kwargs = {'project_id': self.context.project_id, 'name': 'test'} + authz = self.cloud.authorize_security_group_ingress + self.assertRaises(exception.ApiError, authz, self.context, **kwargs) + + def test_authorize_security_group_ingress_already_exists(self): + kwargs = {'project_id': self.context.project_id, 'name': 'test'} + sec = db.security_group_create(self.context, kwargs) + authz = self.cloud.authorize_security_group_ingress + kwargs = {'to_port': '999', 'from_port': '999', 'ip_protocol': 'tcp'} + authz(self.context, group_name=sec['name'], **kwargs) + self.assertRaises(exception.ApiError, authz, self.context, + group_name=sec['name'], **kwargs) + + def test_revoke_security_group_ingress_missing_group_name_or_id(self): + kwargs = {'to_port': '999', 'from_port': '999', 'ip_protocol': 'tcp'} + revoke = self.cloud.revoke_security_group_ingress + self.assertRaises(exception.ApiError, revoke, self.context, **kwargs) + + def test_describe_volumes(self): + """Makes sure describe_volumes works and filters results.""" + vol1 = db.volume_create(self.context, {}) + vol2 = db.volume_create(self.context, {}) + result = self.cloud.describe_volumes(self.context) + self.assertEqual(len(result['volumeSet']), 2) + volume_id = ec2utils.id_to_ec2_vol_id(vol2['id']) + result = self.cloud.describe_volumes(self.context, + volume_id=[volume_id]) + self.assertEqual(len(result['volumeSet']), 1) + self.assertEqual( + ec2utils.ec2_id_to_id(result['volumeSet'][0]['volumeId']), + vol2['id']) + db.volume_destroy(self.context, vol1['id']) + db.volume_destroy(self.context, vol2['id']) + + def test_create_volume_from_snapshot(self): + """Makes sure create_volume works when we specify a snapshot.""" + vol = db.volume_create(self.context, {'size': 1}) + snap = db.snapshot_create(self.context, {'volume_id': vol['id'], + 'volume_size': vol['size'], + 'status': "available"}) + snapshot_id = ec2utils.id_to_ec2_snap_id(snap['id']) + + result = self.cloud.create_volume(self.context, + snapshot_id=snapshot_id) + volume_id = result['volumeId'] + result = self.cloud.describe_volumes(self.context) + self.assertEqual(len(result['volumeSet']), 2) + self.assertEqual(result['volumeSet'][1]['volumeId'], volume_id) + + db.volume_destroy(self.context, ec2utils.ec2_id_to_id(volume_id)) + db.snapshot_destroy(self.context, snap['id']) + db.volume_destroy(self.context, vol['id']) + + def test_describe_availability_zones(self): + """Makes sure describe_availability_zones works and filters results.""" + service1 = db.service_create(self.context, {'host': 'host1_zones', + 'binary': "nova-compute", + 'topic': 'compute', + 'report_count': 0, + 'availability_zone': "zone1"}) + service2 = db.service_create(self.context, {'host': 'host2_zones', + 'binary': "nova-compute", + 'topic': 'compute', + 'report_count': 0, + 'availability_zone': "zone2"}) + result = self.cloud.describe_availability_zones(self.context) + self.assertEqual(len(result['availabilityZoneInfo']), 3) + db.service_destroy(self.context, service1['id']) + db.service_destroy(self.context, service2['id']) + + def test_describe_snapshots(self): + """Makes sure describe_snapshots works and filters results.""" + vol = db.volume_create(self.context, {}) + snap1 = db.snapshot_create(self.context, {'volume_id': vol['id']}) + snap2 = db.snapshot_create(self.context, {'volume_id': vol['id']}) + result = self.cloud.describe_snapshots(self.context) + self.assertEqual(len(result['snapshotSet']), 2) + snapshot_id = ec2utils.id_to_ec2_snap_id(snap2['id']) + result = self.cloud.describe_snapshots(self.context, + snapshot_id=[snapshot_id]) + self.assertEqual(len(result['snapshotSet']), 1) + self.assertEqual( + ec2utils.ec2_id_to_id(result['snapshotSet'][0]['snapshotId']), + snap2['id']) + db.snapshot_destroy(self.context, snap1['id']) + db.snapshot_destroy(self.context, snap2['id']) + db.volume_destroy(self.context, vol['id']) + + def test_create_snapshot(self): + """Makes sure create_snapshot works.""" + vol = db.volume_create(self.context, {'status': "available"}) + volume_id = ec2utils.id_to_ec2_vol_id(vol['id']) + + result = self.cloud.create_snapshot(self.context, + volume_id=volume_id) + snapshot_id = result['snapshotId'] + result = self.cloud.describe_snapshots(self.context) + self.assertEqual(len(result['snapshotSet']), 1) + self.assertEqual(result['snapshotSet'][0]['snapshotId'], snapshot_id) + + db.snapshot_destroy(self.context, ec2utils.ec2_id_to_id(snapshot_id)) + db.volume_destroy(self.context, vol['id']) + + def test_delete_snapshot(self): + """Makes sure delete_snapshot works.""" + vol = db.volume_create(self.context, {'status': "available"}) + snap = db.snapshot_create(self.context, {'volume_id': vol['id'], + 'status': "available"}) + snapshot_id = ec2utils.id_to_ec2_snap_id(snap['id']) + + result = self.cloud.delete_snapshot(self.context, + snapshot_id=snapshot_id) + self.assertTrue(result) + + db.volume_destroy(self.context, vol['id']) + + def test_describe_instances(self): + """Makes sure describe_instances works and filters results.""" + inst1 = db.instance_create(self.context, {'reservation_id': 'a', + 'image_ref': 1, + 'host': 'host1'}) + inst2 = db.instance_create(self.context, {'reservation_id': 'a', + 'image_ref': 1, + 'host': 'host2'}) + comp1 = db.service_create(self.context, {'host': 'host1', + 'availability_zone': 'zone1', + 'topic': "compute"}) + comp2 = db.service_create(self.context, {'host': 'host2', + 'availability_zone': 'zone2', + 'topic': "compute"}) + result = self.cloud.describe_instances(self.context) + result = result['reservationSet'][0] + self.assertEqual(len(result['instancesSet']), 2) + instance_id = ec2utils.id_to_ec2_id(inst2['id']) + result = self.cloud.describe_instances(self.context, + instance_id=[instance_id]) + result = result['reservationSet'][0] + self.assertEqual(len(result['instancesSet']), 1) + self.assertEqual(result['instancesSet'][0]['instanceId'], + instance_id) + self.assertEqual(result['instancesSet'][0] + ['placement']['availabilityZone'], 'zone2') + db.instance_destroy(self.context, inst1['id']) + db.instance_destroy(self.context, inst2['id']) + db.service_destroy(self.context, comp1['id']) + db.service_destroy(self.context, comp2['id']) + + def test_describe_instances_deleted(self): + args1 = {'reservation_id': 'a', 'image_ref': 1, 'host': 'host1'} + inst1 = db.instance_create(self.context, args1) + args2 = {'reservation_id': 'b', 'image_ref': 1, 'host': 'host1'} + inst2 = db.instance_create(self.context, args2) + db.instance_destroy(self.context, inst1.id) + result = self.cloud.describe_instances(self.context) + self.assertEqual(len(result['reservationSet']), 1) + result1 = result['reservationSet'][0]['instancesSet'] + self.assertEqual(result1[0]['instanceId'], + ec2utils.id_to_ec2_id(inst2.id)) + + def _block_device_mapping_create(self, instance_id, mappings): + volumes = [] + for bdm in mappings: + db.block_device_mapping_create(self.context, bdm) + if 'volume_id' in bdm: + values = {'id': bdm['volume_id']} + for bdm_key, vol_key in [('snapshot_id', 'snapshot_id'), + ('snapshot_size', 'volume_size'), + ('delete_on_termination', + 'delete_on_termination')]: + if bdm_key in bdm: + values[vol_key] = bdm[bdm_key] + vol = db.volume_create(self.context, values) + db.volume_attached(self.context, vol['id'], + instance_id, bdm['device_name']) + volumes.append(vol) + return volumes + + def _setUpBlockDeviceMapping(self): + inst1 = db.instance_create(self.context, + {'image_ref': 1, + 'root_device_name': '/dev/sdb1'}) + inst2 = db.instance_create(self.context, + {'image_ref': 2, + 'root_device_name': '/dev/sdc1'}) + + instance_id = inst1['id'] + mappings0 = [ + {'instance_id': instance_id, + 'device_name': '/dev/sdb1', + 'snapshot_id': '1', + 'volume_id': '2'}, + {'instance_id': instance_id, + 'device_name': '/dev/sdb2', + 'volume_id': '3', + 'volume_size': 1}, + {'instance_id': instance_id, + 'device_name': '/dev/sdb3', + 'delete_on_termination': True, + 'snapshot_id': '4', + 'volume_id': '5'}, + {'instance_id': instance_id, + 'device_name': '/dev/sdb4', + 'delete_on_termination': False, + 'snapshot_id': '6', + 'volume_id': '7'}, + {'instance_id': instance_id, + 'device_name': '/dev/sdb5', + 'snapshot_id': '8', + 'volume_id': '9', + 'volume_size': 0}, + {'instance_id': instance_id, + 'device_name': '/dev/sdb6', + 'snapshot_id': '10', + 'volume_id': '11', + 'volume_size': 1}, + {'instance_id': instance_id, + 'device_name': '/dev/sdb7', + 'no_device': True}, + {'instance_id': instance_id, + 'device_name': '/dev/sdb8', + 'virtual_name': 'swap'}, + {'instance_id': instance_id, + 'device_name': '/dev/sdb9', + 'virtual_name': 'ephemeral3'}] + + volumes = self._block_device_mapping_create(instance_id, mappings0) + return (inst1, inst2, volumes) + + def _tearDownBlockDeviceMapping(self, inst1, inst2, volumes): + for vol in volumes: + db.volume_destroy(self.context, vol['id']) + for id in (inst1['id'], inst2['id']): + for bdm in db.block_device_mapping_get_all_by_instance( + self.context, id): + db.block_device_mapping_destroy(self.context, bdm['id']) + db.instance_destroy(self.context, inst2['id']) + db.instance_destroy(self.context, inst1['id']) + + _expected_instance_bdm1 = { + 'instanceId': 'i-00000001', + 'rootDeviceName': '/dev/sdb1', + 'rootDeviceType': 'ebs'} + + _expected_block_device_mapping0 = [ + {'deviceName': '/dev/sdb1', + 'ebs': {'status': 'in-use', + 'deleteOnTermination': False, + 'volumeId': 2, + }}, + {'deviceName': '/dev/sdb2', + 'ebs': {'status': 'in-use', + 'deleteOnTermination': False, + 'volumeId': 3, + }}, + {'deviceName': '/dev/sdb3', + 'ebs': {'status': 'in-use', + 'deleteOnTermination': True, + 'volumeId': 5, + }}, + {'deviceName': '/dev/sdb4', + 'ebs': {'status': 'in-use', + 'deleteOnTermination': False, + 'volumeId': 7, + }}, + {'deviceName': '/dev/sdb5', + 'ebs': {'status': 'in-use', + 'deleteOnTermination': False, + 'volumeId': 9, + }}, + {'deviceName': '/dev/sdb6', + 'ebs': {'status': 'in-use', + 'deleteOnTermination': False, + 'volumeId': 11, }}] + # NOTE(yamahata): swap/ephemeral device case isn't supported yet. + + _expected_instance_bdm2 = { + 'instanceId': 'i-00000002', + 'rootDeviceName': '/dev/sdc1', + 'rootDeviceType': 'instance-store'} + + def test_format_instance_bdm(self): + (inst1, inst2, volumes) = self._setUpBlockDeviceMapping() + + result = {} + self.cloud._format_instance_bdm(self.context, inst1['id'], '/dev/sdb1', + result) + self.assertSubDictMatch( + {'rootDeviceType': self._expected_instance_bdm1['rootDeviceType']}, + result) + self._assertEqualBlockDeviceMapping( + self._expected_block_device_mapping0, result['blockDeviceMapping']) + + result = {} + self.cloud._format_instance_bdm(self.context, inst2['id'], '/dev/sdc1', + result) + self.assertSubDictMatch( + {'rootDeviceType': self._expected_instance_bdm2['rootDeviceType']}, + result) + + self._tearDownBlockDeviceMapping(inst1, inst2, volumes) + + def _assertInstance(self, instance_id): + ec2_instance_id = ec2utils.id_to_ec2_id(instance_id) + result = self.cloud.describe_instances(self.context, + instance_id=[ec2_instance_id]) + result = result['reservationSet'][0] + self.assertEqual(len(result['instancesSet']), 1) + result = result['instancesSet'][0] + self.assertEqual(result['instanceId'], ec2_instance_id) + return result + + def _assertEqualBlockDeviceMapping(self, expected, result): + self.assertEqual(len(expected), len(result)) + for x in expected: + found = False + for y in result: + if x['deviceName'] == y['deviceName']: + self.assertSubDictMatch(x, y) + found = True + break + self.assertTrue(found) + + def test_describe_instances_bdm(self): + """Make sure describe_instances works with root_device_name and + block device mappings + """ + (inst1, inst2, volumes) = self._setUpBlockDeviceMapping() + + result = self._assertInstance(inst1['id']) + self.assertSubDictMatch(self._expected_instance_bdm1, result) + self._assertEqualBlockDeviceMapping( + self._expected_block_device_mapping0, result['blockDeviceMapping']) + + result = self._assertInstance(inst2['id']) + self.assertSubDictMatch(self._expected_instance_bdm2, result) + + self._tearDownBlockDeviceMapping(inst1, inst2, volumes) + + def test_describe_images(self): + describe_images = self.cloud.describe_images + + def fake_detail(meh, context): + return [{'id': 1, 'container_format': 'ami', + 'properties': {'kernel_id': 1, 'ramdisk_id': 1, + 'type': 'machine'}}] + + def fake_show_none(meh, context, id): + raise exception.ImageNotFound(image_id='bad_image_id') + + self.stubs.Set(fake._FakeImageService, 'detail', fake_detail) + # list all + result1 = describe_images(self.context) + result1 = result1['imagesSet'][0] + self.assertEqual(result1['imageId'], 'ami-00000001') + # provided a valid image_id + result2 = describe_images(self.context, ['ami-00000001']) + self.assertEqual(1, len(result2['imagesSet'])) + # provide more than 1 valid image_id + result3 = describe_images(self.context, ['ami-00000001', + 'ami-00000002']) + self.assertEqual(2, len(result3['imagesSet'])) + # provide an non-existing image_id + self.stubs.UnsetAll() + self.stubs.Set(fake._FakeImageService, 'show', fake_show_none) + self.stubs.Set(fake._FakeImageService, 'show_by_name', fake_show_none) + self.assertRaises(exception.ImageNotFound, describe_images, + self.context, ['ami-fake']) + + def assertDictListUnorderedMatch(self, L1, L2, key): + self.assertEqual(len(L1), len(L2)) + for d1 in L1: + self.assertTrue(key in d1) + for d2 in L2: + self.assertTrue(key in d2) + if d1[key] == d2[key]: + self.assertDictMatch(d1, d2) + + def _setUpImageSet(self, create_volumes_and_snapshots=False): + mappings1 = [ + {'device': '/dev/sda1', 'virtual': 'root'}, + + {'device': 'sdb0', 'virtual': 'ephemeral0'}, + {'device': 'sdb1', 'virtual': 'ephemeral1'}, + {'device': 'sdb2', 'virtual': 'ephemeral2'}, + {'device': 'sdb3', 'virtual': 'ephemeral3'}, + {'device': 'sdb4', 'virtual': 'ephemeral4'}, + + {'device': 'sdc0', 'virtual': 'swap'}, + {'device': 'sdc1', 'virtual': 'swap'}, + {'device': 'sdc2', 'virtual': 'swap'}, + {'device': 'sdc3', 'virtual': 'swap'}, + {'device': 'sdc4', 'virtual': 'swap'}] + block_device_mapping1 = [ + {'device_name': '/dev/sdb1', 'snapshot_id': 01234567}, + {'device_name': '/dev/sdb2', 'volume_id': 01234567}, + {'device_name': '/dev/sdb3', 'virtual_name': 'ephemeral5'}, + {'device_name': '/dev/sdb4', 'no_device': True}, + + {'device_name': '/dev/sdc1', 'snapshot_id': 12345678}, + {'device_name': '/dev/sdc2', 'volume_id': 12345678}, + {'device_name': '/dev/sdc3', 'virtual_name': 'ephemeral6'}, + {'device_name': '/dev/sdc4', 'no_device': True}] + image1 = { + 'id': 1, + 'properties': { + 'kernel_id': 1, + 'type': 'machine', + 'image_state': 'available', + 'mappings': mappings1, + 'block_device_mapping': block_device_mapping1, + } + } + + mappings2 = [{'device': '/dev/sda1', 'virtual': 'root'}] + block_device_mapping2 = [{'device_name': '/dev/sdb1', + 'snapshot_id': 01234567}] + image2 = { + 'id': 2, + 'properties': { + 'kernel_id': 2, + 'type': 'machine', + 'root_device_name': '/dev/sdb1', + 'mappings': mappings2, + 'block_device_mapping': block_device_mapping2}} + + def fake_show(meh, context, image_id): + for i in [image1, image2]: + if i['id'] == image_id: + return i + raise exception.ImageNotFound(image_id=image_id) + + def fake_detail(meh, context): + return [image1, image2] + + self.stubs.Set(fake._FakeImageService, 'show', fake_show) + self.stubs.Set(fake._FakeImageService, 'detail', fake_detail) + + volumes = [] + snapshots = [] + if create_volumes_and_snapshots: + for bdm in block_device_mapping1: + if 'volume_id' in bdm: + vol = self._volume_create(bdm['volume_id']) + volumes.append(vol['id']) + if 'snapshot_id' in bdm: + snap = db.snapshot_create(self.context, + {'id': bdm['snapshot_id'], + 'volume_id': 76543210, + 'status': "available", + 'volume_size': 1}) + snapshots.append(snap['id']) + return (volumes, snapshots) + + def _assertImageSet(self, result, root_device_type, root_device_name): + self.assertEqual(1, len(result['imagesSet'])) + result = result['imagesSet'][0] + self.assertTrue('rootDeviceType' in result) + self.assertEqual(result['rootDeviceType'], root_device_type) + self.assertTrue('rootDeviceName' in result) + self.assertEqual(result['rootDeviceName'], root_device_name) + self.assertTrue('blockDeviceMapping' in result) + + return result + + _expected_root_device_name1 = '/dev/sda1' + # NOTE(yamahata): noDevice doesn't make sense when returning mapping + # It makes sense only when user overriding existing + # mapping. + _expected_bdms1 = [ + {'deviceName': '/dev/sdb0', 'virtualName': 'ephemeral0'}, + {'deviceName': '/dev/sdb1', 'ebs': {'snapshotId': + 'snap-00053977'}}, + {'deviceName': '/dev/sdb2', 'ebs': {'snapshotId': + 'vol-00053977'}}, + {'deviceName': '/dev/sdb3', 'virtualName': 'ephemeral5'}, + # {'deviceName': '/dev/sdb4', 'noDevice': True}, + + {'deviceName': '/dev/sdc0', 'virtualName': 'swap'}, + {'deviceName': '/dev/sdc1', 'ebs': {'snapshotId': + 'snap-00bc614e'}}, + {'deviceName': '/dev/sdc2', 'ebs': {'snapshotId': + 'vol-00bc614e'}}, + {'deviceName': '/dev/sdc3', 'virtualName': 'ephemeral6'}, + # {'deviceName': '/dev/sdc4', 'noDevice': True} + ] + + _expected_root_device_name2 = '/dev/sdb1' + _expected_bdms2 = [{'deviceName': '/dev/sdb1', + 'ebs': {'snapshotId': 'snap-00053977'}}] + + # NOTE(yamahata): + # InstanceBlockDeviceMappingItemType + # rootDeviceType + # rootDeviceName + # blockDeviceMapping + # deviceName + # virtualName + # ebs + # snapshotId + # volumeSize + # deleteOnTermination + # noDevice + def test_describe_image_mapping(self): + """test for rootDeviceName and blockDeiceMapping""" + describe_images = self.cloud.describe_images + self._setUpImageSet() + + result = describe_images(self.context, ['ami-00000001']) + result = self._assertImageSet(result, 'instance-store', + self._expected_root_device_name1) + + self.assertDictListUnorderedMatch(result['blockDeviceMapping'], + self._expected_bdms1, 'deviceName') + + result = describe_images(self.context, ['ami-00000002']) + result = self._assertImageSet(result, 'ebs', + self._expected_root_device_name2) + + self.assertDictListUnorderedMatch(result['blockDeviceMapping'], + self._expected_bdms2, 'deviceName') + + self.stubs.UnsetAll() + + def test_describe_image_attribute(self): + describe_image_attribute = self.cloud.describe_image_attribute + + def fake_show(meh, context, id): + return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1, + 'type': 'machine'}, 'container_format': 'ami', + 'is_public': True} + + self.stubs.Set(fake._FakeImageService, 'show', fake_show) + self.stubs.Set(fake._FakeImageService, 'show_by_name', fake_show) + result = describe_image_attribute(self.context, 'ami-00000001', + 'launchPermission') + self.assertEqual([{'group': 'all'}], result['launchPermission']) + + def test_describe_image_attribute_root_device_name(self): + describe_image_attribute = self.cloud.describe_image_attribute + self._setUpImageSet() + + result = describe_image_attribute(self.context, 'ami-00000001', + 'rootDeviceName') + self.assertEqual(result['rootDeviceName'], + self._expected_root_device_name1) + result = describe_image_attribute(self.context, 'ami-00000002', + 'rootDeviceName') + self.assertEqual(result['rootDeviceName'], + self._expected_root_device_name2) + + def test_describe_image_attribute_block_device_mapping(self): + describe_image_attribute = self.cloud.describe_image_attribute + self._setUpImageSet() + + result = describe_image_attribute(self.context, 'ami-00000001', + 'blockDeviceMapping') + self.assertDictListUnorderedMatch(result['blockDeviceMapping'], + self._expected_bdms1, 'deviceName') + result = describe_image_attribute(self.context, 'ami-00000002', + 'blockDeviceMapping') + self.assertDictListUnorderedMatch(result['blockDeviceMapping'], + self._expected_bdms2, 'deviceName') + + 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 fake_metadata + + def fake_update(meh, context, image_id, metadata, data=None): + 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) + self.stubs.Set(fake._FakeImageService, 'update', fake_update) + result = modify_image_attribute(self.context, 'ami-00000001', + 'launchPermission', 'add', + user_group=['all']) + self.assertEqual(True, result['is_public']) + + def test_deregister_image(self): + deregister_image = self.cloud.deregister_image + + def fake_delete(self, context, id): + return None + + self.stubs.Set(fake._FakeImageService, 'delete', fake_delete) + # valid image + result = deregister_image(self.context, 'ami-00000001') + self.assertEqual(result['imageId'], 'ami-00000001') + # invalid image + self.stubs.UnsetAll() + + def fake_detail_empty(self, context): + return [] + + self.stubs.Set(fake._FakeImageService, 'detail', fake_detail_empty) + self.assertRaises(exception.ImageNotFound, deregister_image, + self.context, 'ami-bad001') + + def test_deregister_image_wrong_container_type(self): + deregister_image = self.cloud.deregister_image + + def fake_delete(self, context, id): + return None + + self.stubs.Set(fake._FakeImageService, 'delete', fake_delete) + self.assertRaises(exception.NotFound, deregister_image, self.context, + 'aki-00000001') + + def _run_instance(self, **kwargs): + rv = self.cloud.run_instances(self.context, **kwargs) + instance_id = rv['instancesSet'][0]['instanceId'] + return instance_id + + def _run_instance_wait(self, **kwargs): + ec2_instance_id = self._run_instance(**kwargs) + self._wait_for_running(ec2_instance_id) + return ec2_instance_id + + def test_console_output(self): + instance_id = self._run_instance( + image_id='ami-1', + instance_type=FLAGS.default_instance_type, + max_count=1) + output = self.cloud.get_console_output(context=self.context, + instance_id=[instance_id]) + self.assertEquals(b64decode(output['output']), 'FAKE CONSOLE?OUTPUT') + # TODO(soren): We need this until we can stop polling in the rpc code + # for unit tests. + rv = self.cloud.terminate_instances(self.context, [instance_id]) + + def test_ajax_console(self): + instance_id = self._run_instance(image_id='ami-1') + output = self.cloud.get_ajax_console(context=self.context, + instance_id=[instance_id]) + self.assertEquals(output['url'], + '%s/?token=FAKETOKEN' % FLAGS.ajax_console_proxy_url) + # TODO(soren): We need this until we can stop polling in the rpc code + # for unit tests. + rv = self.cloud.terminate_instances(self.context, [instance_id]) + + def test_key_generation(self): + result = self._create_key('test') + private_key = result['private_key'] + key = RSA.load_key_string(private_key, callback=lambda: None) + bio = BIO.MemoryBuffer() + public_key = db.key_pair_get(self.context, + self.context.user_id, + 'test')['public_key'] + key.save_pub_key_bio(bio) + converted = crypto.ssl_pub_to_ssh_pub(bio.read()) + # assert key fields are equal + self.assertEqual(public_key.split(" ")[1].strip(), + converted.split(" ")[1].strip()) + + def test_describe_key_pairs(self): + self._create_key('test1') + self._create_key('test2') + result = self.cloud.describe_key_pairs(self.context) + keys = result["keySet"] + self.assertTrue(filter(lambda k: k['keyName'] == 'test1', keys)) + self.assertTrue(filter(lambda k: k['keyName'] == 'test2', keys)) + + def test_import_public_key(self): + # test when user provides all values + result1 = self.cloud.import_public_key(self.context, + 'testimportkey1', + 'mytestpubkey', + 'mytestfprint') + self.assertTrue(result1) + keydata = db.key_pair_get(self.context, + self.context.user_id, + 'testimportkey1') + self.assertEqual('mytestpubkey', keydata['public_key']) + self.assertEqual('mytestfprint', keydata['fingerprint']) + # test when user omits fingerprint + pubkey_path = os.path.join(os.path.dirname(__file__), 'public_key') + f = open(pubkey_path + '/dummy.pub', 'r') + dummypub = f.readline().rstrip() + f.close + f = open(pubkey_path + '/dummy.fingerprint', 'r') + dummyfprint = f.readline().rstrip() + f.close + result2 = self.cloud.import_public_key(self.context, + 'testimportkey2', + dummypub) + self.assertTrue(result2) + keydata = db.key_pair_get(self.context, + self.context.user_id, + 'testimportkey2') + self.assertEqual(dummypub, keydata['public_key']) + self.assertEqual(dummyfprint, keydata['fingerprint']) + + def test_delete_key_pair(self): + self._create_key('test') + self.cloud.delete_key_pair(self.context, 'test') + + def test_run_instances(self): + kwargs = {'image_id': FLAGS.default_image, + 'instance_type': FLAGS.default_instance_type, + 'max_count': 1} + run_instances = self.cloud.run_instances + result = run_instances(self.context, **kwargs) + instance = result['instancesSet'][0] + self.assertEqual(instance['imageId'], 'ami-00000001') + self.assertEqual(instance['displayName'], 'Server 1') + self.assertEqual(instance['instanceId'], 'i-00000001') + self.assertEqual(instance['instanceState']['name'], 'running') + self.assertEqual(instance['instanceType'], 'm1.small') + + def test_run_instances_image_state_none(self): + kwargs = {'image_id': FLAGS.default_image, + 'instance_type': FLAGS.default_instance_type, + 'max_count': 1} + run_instances = self.cloud.run_instances + + def fake_show_no_state(self, context, id): + return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1, + 'type': 'machine'}, 'container_format': 'ami'} + + self.stubs.UnsetAll() + self.stubs.Set(fake._FakeImageService, 'show', fake_show_no_state) + self.assertRaises(exception.ApiError, run_instances, + self.context, **kwargs) + + def test_run_instances_image_state_invalid(self): + kwargs = {'image_id': FLAGS.default_image, + 'instance_type': FLAGS.default_instance_type, + 'max_count': 1} + run_instances = self.cloud.run_instances + + def fake_show_decrypt(self, context, id): + return {'id': 1, 'container_format': 'ami', + 'properties': {'kernel_id': 1, 'ramdisk_id': 1, + 'type': 'machine', 'image_state': 'decrypting'}} + + self.stubs.UnsetAll() + self.stubs.Set(fake._FakeImageService, 'show', fake_show_decrypt) + self.assertRaises(exception.ApiError, run_instances, + self.context, **kwargs) + + def test_run_instances_image_status_active(self): + kwargs = {'image_id': FLAGS.default_image, + 'instance_type': FLAGS.default_instance_type, + 'max_count': 1} + run_instances = self.cloud.run_instances + + def fake_show_stat_active(self, context, id): + return {'id': 1, 'container_format': 'ami', + 'properties': {'kernel_id': 1, 'ramdisk_id': 1, + 'type': 'machine'}, 'status': 'active'} + + self.stubs.Set(fake._FakeImageService, 'show', fake_show_stat_active) + + result = run_instances(self.context, **kwargs) + self.assertEqual(len(result['instancesSet']), 1) + + def test_terminate_instances(self): + inst1 = db.instance_create(self.context, {'reservation_id': 'a', + 'image_ref': 1, + 'host': 'host1'}) + terminate_instances = self.cloud.terminate_instances + # valid instance_id + result = terminate_instances(self.context, ['i-00000001']) + self.assertTrue(result) + # non-existing instance_id + self.assertRaises(exception.InstanceNotFound, terminate_instances, + self.context, ['i-2']) + db.instance_destroy(self.context, inst1['id']) + + def test_update_of_instance_display_fields(self): + inst = db.instance_create(self.context, {}) + ec2_id = ec2utils.id_to_ec2_id(inst['id']) + self.cloud.update_instance(self.context, ec2_id, + display_name='c00l 1m4g3') + inst = db.instance_get(self.context, inst['id']) + self.assertEqual('c00l 1m4g3', inst['display_name']) + db.instance_destroy(self.context, inst['id']) + + def test_update_of_instance_wont_update_private_fields(self): + inst = db.instance_create(self.context, {}) + host = inst['host'] + ec2_id = ec2utils.id_to_ec2_id(inst['id']) + self.cloud.update_instance(self.context, ec2_id, + display_name='c00l 1m4g3', + host='otherhost') + inst = db.instance_get(self.context, inst['id']) + self.assertEqual(host, inst['host']) + db.instance_destroy(self.context, inst['id']) + + def test_update_of_volume_display_fields(self): + vol = db.volume_create(self.context, {}) + self.cloud.update_volume(self.context, + ec2utils.id_to_ec2_vol_id(vol['id']), + display_name='c00l v0lum3') + vol = db.volume_get(self.context, vol['id']) + self.assertEqual('c00l v0lum3', vol['display_name']) + db.volume_destroy(self.context, vol['id']) + + def test_update_of_volume_wont_update_private_fields(self): + vol = db.volume_create(self.context, {}) + self.cloud.update_volume(self.context, + ec2utils.id_to_ec2_vol_id(vol['id']), + mountpoint='/not/here') + vol = db.volume_get(self.context, vol['id']) + self.assertEqual(None, vol['mountpoint']) + db.volume_destroy(self.context, vol['id']) + + def _restart_compute_service(self, periodic_interval=None): + """restart compute service. NOTE: fake driver forgets all instances.""" + self.compute.kill() + if periodic_interval: + self.compute = self.start_service( + 'compute', periodic_interval=periodic_interval) + else: + self.compute = self.start_service('compute') + + def _wait_for_state(self, ctxt, instance_id, predicate): + """Wait for a stopped instance to be a given state""" + id = ec2utils.ec2_id_to_id(instance_id) + while True: + info = self.cloud.compute_api.get(context=ctxt, instance_id=id) + LOG.debug(info) + if predicate(info): + break + greenthread.sleep(1) + + def _wait_for_running(self, instance_id): + def is_running(info): + vm_state = info["vm_state"] + task_state = info["task_state"] + return vm_state == vm_states.ACTIVE and task_state == None + self._wait_for_state(self.context, instance_id, is_running) + + def _wait_for_stopped(self, instance_id): + def is_stopped(info): + vm_state = info["vm_state"] + task_state = info["task_state"] + return vm_state == vm_states.STOPPED and task_state == None + self._wait_for_state(self.context, instance_id, is_stopped) + + def _wait_for_terminate(self, instance_id): + def is_deleted(info): + return info['deleted'] + elevated = self.context.elevated(read_deleted=True) + self._wait_for_state(elevated, instance_id, is_deleted) + + def test_stop_start_instance(self): + """Makes sure stop/start instance works""" + # enforce periodic tasks run in short time to avoid wait for 60s. + self._restart_compute_service(periodic_interval=0.3) + + kwargs = {'image_id': 'ami-1', + 'instance_type': FLAGS.default_instance_type, + 'max_count': 1, } + instance_id = self._run_instance_wait(**kwargs) + + # a running instance can't be started. It is just ignored. + result = self.cloud.start_instances(self.context, [instance_id]) + greenthread.sleep(0.3) + self.assertTrue(result) + + result = self.cloud.stop_instances(self.context, [instance_id]) + greenthread.sleep(0.3) + self.assertTrue(result) + self._wait_for_stopped(instance_id) + + result = self.cloud.start_instances(self.context, [instance_id]) + greenthread.sleep(0.3) + self.assertTrue(result) + self._wait_for_running(instance_id) + + result = self.cloud.stop_instances(self.context, [instance_id]) + greenthread.sleep(0.3) + self.assertTrue(result) + self._wait_for_stopped(instance_id) + + result = self.cloud.terminate_instances(self.context, [instance_id]) + greenthread.sleep(0.3) + self.assertTrue(result) + + self._restart_compute_service() + + def _volume_create(self, volume_id=None): + kwargs = {'status': 'available', + 'host': self.volume.host, + 'size': 1, + 'attach_status': 'detached', } + if volume_id: + kwargs['id'] = volume_id + return db.volume_create(self.context, kwargs) + + def _assert_volume_attached(self, vol, instance_id, mountpoint): + self.assertEqual(vol['instance_id'], instance_id) + self.assertEqual(vol['mountpoint'], mountpoint) + self.assertEqual(vol['status'], "in-use") + self.assertEqual(vol['attach_status'], "attached") + + def _assert_volume_detached(self, vol): + self.assertEqual(vol['instance_id'], None) + self.assertEqual(vol['mountpoint'], None) + self.assertEqual(vol['status'], "available") + self.assertEqual(vol['attach_status'], "detached") + + def test_stop_start_with_volume(self): + """Make sure run instance with block device mapping works""" + + # enforce periodic tasks run in short time to avoid wait for 60s. + self._restart_compute_service(periodic_interval=0.3) + + vol1 = self._volume_create() + vol2 = self._volume_create() + kwargs = {'image_id': 'ami-1', + 'instance_type': FLAGS.default_instance_type, + 'max_count': 1, + 'block_device_mapping': [{'device_name': '/dev/vdb', + 'volume_id': vol1['id'], + 'delete_on_termination': False}, + {'device_name': '/dev/vdc', + 'volume_id': vol2['id'], + 'delete_on_termination': True}, + ]} + ec2_instance_id = self._run_instance_wait(**kwargs) + instance_id = ec2utils.ec2_id_to_id(ec2_instance_id) + + vols = db.volume_get_all_by_instance(self.context, instance_id) + self.assertEqual(len(vols), 2) + for vol in vols: + self.assertTrue(vol['id'] == vol1['id'] or vol['id'] == vol2['id']) + + vol = db.volume_get(self.context, vol1['id']) + self._assert_volume_attached(vol, instance_id, '/dev/vdb') + + vol = db.volume_get(self.context, vol2['id']) + self._assert_volume_attached(vol, instance_id, '/dev/vdc') + + result = self.cloud.stop_instances(self.context, [ec2_instance_id]) + self.assertTrue(result) + self._wait_for_stopped(ec2_instance_id) + + vol = db.volume_get(self.context, vol1['id']) + self._assert_volume_detached(vol) + vol = db.volume_get(self.context, vol2['id']) + self._assert_volume_detached(vol) + + self.cloud.start_instances(self.context, [ec2_instance_id]) + self._wait_for_running(ec2_instance_id) + vols = db.volume_get_all_by_instance(self.context, instance_id) + self.assertEqual(len(vols), 2) + for vol in vols: + self.assertTrue(vol['id'] == vol1['id'] or vol['id'] == vol2['id']) + self.assertTrue(vol['mountpoint'] == '/dev/vdb' or + vol['mountpoint'] == '/dev/vdc') + self.assertEqual(vol['instance_id'], instance_id) + self.assertEqual(vol['status'], "in-use") + self.assertEqual(vol['attach_status'], "attached") + + self.cloud.terminate_instances(self.context, [ec2_instance_id]) + greenthread.sleep(0.3) + + admin_ctxt = context.get_admin_context(read_deleted=False) + vol = db.volume_get(admin_ctxt, vol1['id']) + self.assertFalse(vol['deleted']) + db.volume_destroy(self.context, vol1['id']) + + greenthread.sleep(0.3) + admin_ctxt = context.get_admin_context(read_deleted=True) + vol = db.volume_get(admin_ctxt, vol2['id']) + self.assertTrue(vol['deleted']) + + self._restart_compute_service() + + def test_stop_with_attached_volume(self): + """Make sure attach info is reflected to block device mapping""" + # enforce periodic tasks run in short time to avoid wait for 60s. + self._restart_compute_service(periodic_interval=0.3) + + vol1 = self._volume_create() + vol2 = self._volume_create() + kwargs = {'image_id': 'ami-1', + 'instance_type': FLAGS.default_instance_type, + 'max_count': 1, + 'block_device_mapping': [{'device_name': '/dev/vdb', + 'volume_id': vol1['id'], + 'delete_on_termination': True}]} + ec2_instance_id = self._run_instance_wait(**kwargs) + instance_id = ec2utils.ec2_id_to_id(ec2_instance_id) + + vols = db.volume_get_all_by_instance(self.context, instance_id) + self.assertEqual(len(vols), 1) + for vol in vols: + self.assertEqual(vol['id'], vol1['id']) + self._assert_volume_attached(vol, instance_id, '/dev/vdb') + + vol = db.volume_get(self.context, vol2['id']) + self._assert_volume_detached(vol) + + self.cloud.compute_api.attach_volume(self.context, + instance_id=instance_id, + volume_id=vol2['id'], + device='/dev/vdc') + greenthread.sleep(0.3) + vol = db.volume_get(self.context, vol2['id']) + self._assert_volume_attached(vol, instance_id, '/dev/vdc') + + self.cloud.compute_api.detach_volume(self.context, + volume_id=vol1['id']) + greenthread.sleep(0.3) + vol = db.volume_get(self.context, vol1['id']) + self._assert_volume_detached(vol) + + result = self.cloud.stop_instances(self.context, [ec2_instance_id]) + self.assertTrue(result) + self._wait_for_stopped(ec2_instance_id) + + for vol_id in (vol1['id'], vol2['id']): + vol = db.volume_get(self.context, vol_id) + self._assert_volume_detached(vol) + + self.cloud.start_instances(self.context, [ec2_instance_id]) + self._wait_for_running(ec2_instance_id) + vols = db.volume_get_all_by_instance(self.context, instance_id) + self.assertEqual(len(vols), 1) + for vol in vols: + self.assertEqual(vol['id'], vol2['id']) + self._assert_volume_attached(vol, instance_id, '/dev/vdc') + + vol = db.volume_get(self.context, vol1['id']) + self._assert_volume_detached(vol) + + self.cloud.terminate_instances(self.context, [ec2_instance_id]) + greenthread.sleep(0.3) + + for vol_id in (vol1['id'], vol2['id']): + vol = db.volume_get(self.context, vol_id) + self.assertEqual(vol['id'], vol_id) + self._assert_volume_detached(vol) + db.volume_destroy(self.context, vol_id) + + self._restart_compute_service() + + def _create_snapshot(self, ec2_volume_id): + result = self.cloud.create_snapshot(self.context, + volume_id=ec2_volume_id) + greenthread.sleep(0.3) + return result['snapshotId'] + + def test_run_with_snapshot(self): + """Makes sure run/stop/start instance with snapshot works.""" + vol = self._volume_create() + ec2_volume_id = ec2utils.id_to_ec2_vol_id(vol['id']) + + ec2_snapshot1_id = self._create_snapshot(ec2_volume_id) + snapshot1_id = ec2utils.ec2_id_to_id(ec2_snapshot1_id) + ec2_snapshot2_id = self._create_snapshot(ec2_volume_id) + snapshot2_id = ec2utils.ec2_id_to_id(ec2_snapshot2_id) + + kwargs = {'image_id': 'ami-1', + 'instance_type': FLAGS.default_instance_type, + 'max_count': 1, + 'block_device_mapping': [{'device_name': '/dev/vdb', + 'snapshot_id': snapshot1_id, + 'delete_on_termination': False, }, + {'device_name': '/dev/vdc', + 'snapshot_id': snapshot2_id, + 'delete_on_termination': True}]} + ec2_instance_id = self._run_instance_wait(**kwargs) + instance_id = ec2utils.ec2_id_to_id(ec2_instance_id) + + vols = db.volume_get_all_by_instance(self.context, instance_id) + self.assertEqual(len(vols), 2) + vol1_id = None + vol2_id = None + for vol in vols: + snapshot_id = vol['snapshot_id'] + if snapshot_id == snapshot1_id: + vol1_id = vol['id'] + mountpoint = '/dev/vdb' + elif snapshot_id == snapshot2_id: + vol2_id = vol['id'] + mountpoint = '/dev/vdc' + else: + self.fail() + + self._assert_volume_attached(vol, instance_id, mountpoint) + + self.assertTrue(vol1_id) + self.assertTrue(vol2_id) + + self.cloud.terminate_instances(self.context, [ec2_instance_id]) + greenthread.sleep(0.3) + self._wait_for_terminate(ec2_instance_id) + + greenthread.sleep(0.3) + admin_ctxt = context.get_admin_context(read_deleted=False) + vol = db.volume_get(admin_ctxt, vol1_id) + self._assert_volume_detached(vol) + self.assertFalse(vol['deleted']) + db.volume_destroy(self.context, vol1_id) + + greenthread.sleep(0.3) + admin_ctxt = context.get_admin_context(read_deleted=True) + vol = db.volume_get(admin_ctxt, vol2_id) + self.assertTrue(vol['deleted']) + + for snapshot_id in (ec2_snapshot1_id, ec2_snapshot2_id): + self.cloud.delete_snapshot(self.context, snapshot_id) + greenthread.sleep(0.3) + db.volume_destroy(self.context, vol['id']) + + def test_create_image(self): + """Make sure that CreateImage works""" + # enforce periodic tasks run in short time to avoid wait for 60s. + self._restart_compute_service(periodic_interval=0.3) + + (volumes, snapshots) = self._setUpImageSet( + create_volumes_and_snapshots=True) + + kwargs = {'image_id': 'ami-1', + 'instance_type': FLAGS.default_instance_type, + 'max_count': 1} + ec2_instance_id = self._run_instance_wait(**kwargs) + + # TODO(yamahata): s3._s3_create() can't be tested easily by unit test + # as there is no unit test for s3.create() + ## result = self.cloud.create_image(self.context, ec2_instance_id, + ## no_reboot=True) + ## ec2_image_id = result['imageId'] + ## created_image = self.cloud.describe_images(self.context, + ## [ec2_image_id]) + + self.cloud.terminate_instances(self.context, [ec2_instance_id]) + for vol in volumes: + db.volume_destroy(self.context, vol) + for snap in snapshots: + db.snapshot_destroy(self.context, snap) + # 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'}], + 'vm_state': vm_states.STOPPED, + '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': 'stopped'}) + 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/public_key/dummy.fingerprint b/nova/tests/public_key/dummy.fingerprint deleted file mode 100644 index 715bca27a..000000000 --- a/nova/tests/public_key/dummy.fingerprint +++ /dev/null @@ -1 +0,0 @@ -1c:87:d1:d9:32:fd:62:3c:78:2b:c0:ad:c0:15:88:df diff --git a/nova/tests/public_key/dummy.pub b/nova/tests/public_key/dummy.pub deleted file mode 100644 index d4cf2bc0d..000000000 --- a/nova/tests/public_key/dummy.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-dss AAAAB3NzaC1kc3MAAACBAMGJlY9XEIm2X234pdO5yFWMp2JuOQx8U0E815IVXhmKxYCBK9ZakgZOIQmPbXoGYyV+mziDPp6HJ0wKYLQxkwLEFr51fAZjWQvRss0SinURRuLkockDfGFtD4pYJthekr/rlqMKlBSDUSpGq8jUWW60UJ18FGooFpxR7ESqQRx/AAAAFQC96LRglaUeeP+E8U/yblEJocuiWwAAAIA3XiMR8Skiz/0aBm5K50SeQznQuMJTyzt9S9uaz5QZWiFu69hOyGSFGw8fqgxEkXFJIuHobQQpGYQubLW0NdaYRqyE/Vud3JUJUb8Texld6dz8vGemyB5d1YvtSeHIo8/BGv2msOqR3u5AZTaGCBD9DhpSGOKHEdNjTtvpPd8S8gAAAIBociGZ5jf09iHLVENhyXujJbxfGRPsyNTyARJfCOGl0oFV6hEzcQyw8U/ePwjgvjc2UizMWLl8tsb2FXKHRdc2v+ND3Us+XqKQ33X3ADP4FZ/+Oj213gMyhCmvFTP0u5FmHog9My4CB7YcIWRuUR42WlhQ2IfPvKwUoTk3R+T6Og== www-data@mk diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py deleted file mode 100644 index 7fe353b3d..000000000 --- a/nova/tests/test_cloud.py +++ /dev/null @@ -1,1623 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# 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. -import mox - -import functools - -from base64 import b64decode -from M2Crypto import BIO -from M2Crypto import RSA -import os - -from eventlet import greenthread - -from nova import context -from nova import crypto -from nova import db -from nova import exception -from nova import flags -from nova import log as logging -from nova import network -from nova import rpc -from nova import test -from nova import utils -from nova.api.ec2 import cloud -from nova.api.ec2 import ec2utils -from nova.compute import vm_states -from nova.image import fake - - -FLAGS = flags.FLAGS -LOG = logging.getLogger('nova.tests.cloud') - - -class CloudTestCase(test.TestCase): - def setUp(self): - super(CloudTestCase, self).setUp() - self.flags(connection_type='fake', - stub_network=True) - - # set up our cloud - self.cloud = cloud.CloudController() - - # set up services - self.compute = self.start_service('compute') - self.scheduter = self.start_service('scheduler') - self.network = self.start_service('network') - self.volume = self.start_service('volume') - self.image_service = utils.import_object(FLAGS.image_service) - - self.user_id = 'fake' - self.project_id = 'fake' - self.context = context.RequestContext(self.user_id, - self.project_id, - True) - - def fake_show(meh, context, id): - return {'id': 1, 'container_format': 'ami', - 'properties': {'kernel_id': 1, 'ramdisk_id': 1, - 'type': 'machine', 'image_state': 'available'}} - - self.stubs.Set(fake._FakeImageService, 'show', fake_show) - self.stubs.Set(fake._FakeImageService, 'show_by_name', fake_show) - - # NOTE(vish): set up a manual wait so rpc.cast has a chance to finish - rpc_cast = rpc.cast - - def finish_cast(*args, **kwargs): - rpc_cast(*args, **kwargs) - greenthread.sleep(0.2) - - self.stubs.Set(rpc, 'cast', finish_cast) - - def _create_key(self, name): - # NOTE(vish): create depends on pool, so just call helper directly - return cloud._gen_key(self.context, self.context.user_id, name) - - def test_describe_regions(self): - """Makes sure describe regions runs without raising an exception""" - result = self.cloud.describe_regions(self.context) - self.assertEqual(len(result['regionInfo']), 1) - self.flags(region_list=["one=test_host1", "two=test_host2"]) - result = self.cloud.describe_regions(self.context) - self.assertEqual(len(result['regionInfo']), 2) - - def test_describe_addresses(self): - """Makes sure describe addresses runs without raising an exception""" - address = "10.10.10.10" - db.floating_ip_create(self.context, - {'address': address, - 'host': self.network.host}) - self.cloud.allocate_address(self.context) - self.cloud.describe_addresses(self.context) - self.cloud.release_address(self.context, - public_ip=address) - db.floating_ip_destroy(self.context, address) - - def test_allocate_address(self): - address = "10.10.10.10" - allocate = self.cloud.allocate_address - db.floating_ip_create(self.context, - {'address': address, - 'host': self.network.host}) - self.assertEqual(allocate(self.context)['publicIp'], address) - db.floating_ip_destroy(self.context, address) - self.assertRaises(exception.NoMoreFloatingIps, - allocate, - self.context) - - def test_release_address(self): - address = "10.10.10.10" - allocate = self.cloud.allocate_address - db.floating_ip_create(self.context, - {'address': address, - 'host': self.network.host}) - result = self.cloud.release_address(self.context, address) - self.assertEqual(result['releaseResponse'], ['Address released.']) - - def test_release_address_still_associated(self): - address = "10.10.10.10" - fixed_ip = {'instance': {'id': 1}} - floating_ip = {'id': 0, - 'address': address, - 'fixed_ip_id': 0, - 'fixed_ip': fixed_ip, - 'project_id': None, - 'auto_assigned': False} - network_api = network.api.API() - self.mox.StubOutWithMock(network_api.db, 'floating_ip_get_by_address') - network_api.db.floating_ip_get_by_address(mox.IgnoreArg(), - mox.IgnoreArg()).AndReturn(floating_ip) - self.mox.ReplayAll() - release = self.cloud.release_address - # ApiError: Floating ip is in use. Disassociate it before releasing. - self.assertRaises(exception.ApiError, release, self.context, address) - - def test_associate_disassociate_address(self): - """Verifies associate runs cleanly without raising an exception""" - address = "10.10.10.10" - db.floating_ip_create(self.context, {'address': address}) - self.cloud.allocate_address(self.context) - # TODO(jkoelker) Probably need to query for instance_type_id and - # make sure we get a valid one - inst = db.instance_create(self.context, {'host': self.compute.host, - 'instance_type_id': 1}) - networks = db.network_get_all(self.context) - for network in networks: - db.network_update(self.context, network['id'], - {'host': self.network.host}) - project_id = self.context.project_id - type_id = inst['instance_type_id'] - ips = self.network.allocate_for_instance(self.context, - instance_id=inst['id'], - host=inst['host'], - vpn=None, - instance_type_id=type_id, - project_id=project_id) - # TODO(jkoelker) Make this mas bueno - self.assertTrue(ips) - self.assertTrue('ips' in ips[0][1]) - self.assertTrue(ips[0][1]['ips']) - self.assertTrue('ip' in ips[0][1]['ips'][0]) - - fixed = ips[0][1]['ips'][0]['ip'] - - ec2_id = ec2utils.id_to_ec2_id(inst['id']) - self.cloud.associate_address(self.context, - instance_id=ec2_id, - public_ip=address) - self.cloud.disassociate_address(self.context, - public_ip=address) - self.cloud.release_address(self.context, - public_ip=address) - self.network.deallocate_fixed_ip(self.context, fixed) - db.instance_destroy(self.context, inst['id']) - db.floating_ip_destroy(self.context, address) - - def test_describe_security_groups(self): - """Makes sure describe_security_groups works and filters results.""" - sec = db.security_group_create(self.context, - {'project_id': self.context.project_id, - 'name': 'test'}) - result = self.cloud.describe_security_groups(self.context) - # NOTE(vish): should have the default group as well - self.assertEqual(len(result['securityGroupInfo']), 2) - result = self.cloud.describe_security_groups(self.context, - group_name=[sec['name']]) - self.assertEqual(len(result['securityGroupInfo']), 1) - self.assertEqual( - result['securityGroupInfo'][0]['groupName'], - sec['name']) - db.security_group_destroy(self.context, sec['id']) - - def test_describe_security_groups_by_id(self): - sec = db.security_group_create(self.context, - {'project_id': self.context.project_id, - 'name': 'test'}) - result = self.cloud.describe_security_groups(self.context, - group_id=[sec['id']]) - self.assertEqual(len(result['securityGroupInfo']), 1) - self.assertEqual( - result['securityGroupInfo'][0]['groupName'], - sec['name']) - default = db.security_group_get_by_name(self.context, - self.context.project_id, - 'default') - result = self.cloud.describe_security_groups(self.context, - group_id=[default['id']]) - self.assertEqual(len(result['securityGroupInfo']), 1) - self.assertEqual( - result['securityGroupInfo'][0]['groupName'], - 'default') - db.security_group_destroy(self.context, sec['id']) - - def test_create_delete_security_group(self): - descript = 'test description' - create = self.cloud.create_security_group - result = create(self.context, 'testgrp', descript) - group_descript = result['securityGroupSet'][0]['groupDescription'] - self.assertEqual(descript, group_descript) - delete = self.cloud.delete_security_group - self.assertTrue(delete(self.context, 'testgrp')) - - def test_delete_security_group_by_id(self): - sec = db.security_group_create(self.context, - {'project_id': self.context.project_id, - 'name': 'test'}) - delete = self.cloud.delete_security_group - self.assertTrue(delete(self.context, group_id=sec['id'])) - - def test_delete_security_group_with_bad_name(self): - delete = self.cloud.delete_security_group - notfound = exception.SecurityGroupNotFound - self.assertRaises(notfound, delete, self.context, 'badname') - - def test_delete_security_group_with_bad_group_id(self): - delete = self.cloud.delete_security_group - notfound = exception.SecurityGroupNotFound - self.assertRaises(notfound, delete, self.context, group_id=999) - - def test_delete_security_group_no_params(self): - delete = self.cloud.delete_security_group - self.assertRaises(exception.ApiError, delete, self.context) - - def test_authorize_security_group_ingress(self): - kwargs = {'project_id': self.context.project_id, 'name': 'test'} - sec = db.security_group_create(self.context, kwargs) - authz = self.cloud.authorize_security_group_ingress - kwargs = {'to_port': '999', 'from_port': '999', 'ip_protocol': 'tcp'} - self.assertTrue(authz(self.context, group_name=sec['name'], **kwargs)) - - def test_authorize_security_group_ingress_ip_permissions_ip_ranges(self): - kwargs = {'project_id': self.context.project_id, 'name': 'test'} - sec = db.security_group_create(self.context, kwargs) - authz = self.cloud.authorize_security_group_ingress - kwargs = {'ip_permissions': [{'to_port': 81, 'from_port': 81, - 'ip_ranges': - {'1': {'cidr_ip': u'0.0.0.0/0'}, - '2': {'cidr_ip': u'10.10.10.10/32'}}, - 'ip_protocol': u'tcp'}]} - self.assertTrue(authz(self.context, group_name=sec['name'], **kwargs)) - - def test_authorize_security_group_fail_missing_source_group(self): - kwargs = {'project_id': self.context.project_id, 'name': 'test'} - sec = db.security_group_create(self.context, kwargs) - authz = self.cloud.authorize_security_group_ingress - kwargs = {'ip_permissions': [{'to_port': 81, 'from_port': 81, - 'ip_ranges':{'1': {'cidr_ip': u'0.0.0.0/0'}, - '2': {'cidr_ip': u'10.10.10.10/32'}}, - 'groups': {'1': {'user_id': u'someuser', - 'group_name': u'somegroup1'}}, - 'ip_protocol': u'tcp'}]} - self.assertRaises(exception.SecurityGroupNotFound, authz, - self.context, group_name=sec['name'], **kwargs) - - def test_authorize_security_group_ingress_ip_permissions_groups(self): - kwargs = {'project_id': self.context.project_id, 'name': 'test'} - sec = db.security_group_create(self.context, - {'project_id': 'someuser', - 'name': 'somegroup1'}) - sec = db.security_group_create(self.context, - {'project_id': 'someuser', - 'name': 'othergroup2'}) - sec = db.security_group_create(self.context, kwargs) - authz = self.cloud.authorize_security_group_ingress - kwargs = {'ip_permissions': [{'to_port': 81, 'from_port': 81, - 'groups': {'1': {'user_id': u'someuser', - 'group_name': u'somegroup1'}, - '2': {'user_id': u'someuser', - 'group_name': u'othergroup2'}}, - 'ip_protocol': u'tcp'}]} - self.assertTrue(authz(self.context, group_name=sec['name'], **kwargs)) - - def test_revoke_security_group_ingress(self): - kwargs = {'project_id': self.context.project_id, 'name': 'test'} - sec = db.security_group_create(self.context, kwargs) - authz = self.cloud.authorize_security_group_ingress - kwargs = {'to_port': '999', 'from_port': '999', 'ip_protocol': 'tcp'} - authz(self.context, group_id=sec['id'], **kwargs) - revoke = self.cloud.revoke_security_group_ingress - self.assertTrue(revoke(self.context, group_name=sec['name'], **kwargs)) - - def test_authorize_revoke_security_group_ingress_by_id(self): - sec = db.security_group_create(self.context, - {'project_id': self.context.project_id, - 'name': 'test'}) - authz = self.cloud.authorize_security_group_ingress - kwargs = {'to_port': '999', 'from_port': '999', 'ip_protocol': 'tcp'} - authz(self.context, group_id=sec['id'], **kwargs) - revoke = self.cloud.revoke_security_group_ingress - self.assertTrue(revoke(self.context, group_id=sec['id'], **kwargs)) - - def test_authorize_security_group_ingress_missing_protocol_params(self): - sec = db.security_group_create(self.context, - {'project_id': self.context.project_id, - 'name': 'test'}) - authz = self.cloud.authorize_security_group_ingress - self.assertRaises(exception.ApiError, authz, self.context, 'test') - - def test_authorize_security_group_ingress_missing_group_name_or_id(self): - kwargs = {'project_id': self.context.project_id, 'name': 'test'} - authz = self.cloud.authorize_security_group_ingress - self.assertRaises(exception.ApiError, authz, self.context, **kwargs) - - def test_authorize_security_group_ingress_already_exists(self): - kwargs = {'project_id': self.context.project_id, 'name': 'test'} - sec = db.security_group_create(self.context, kwargs) - authz = self.cloud.authorize_security_group_ingress - kwargs = {'to_port': '999', 'from_port': '999', 'ip_protocol': 'tcp'} - authz(self.context, group_name=sec['name'], **kwargs) - self.assertRaises(exception.ApiError, authz, self.context, - group_name=sec['name'], **kwargs) - - def test_revoke_security_group_ingress_missing_group_name_or_id(self): - kwargs = {'to_port': '999', 'from_port': '999', 'ip_protocol': 'tcp'} - revoke = self.cloud.revoke_security_group_ingress - self.assertRaises(exception.ApiError, revoke, self.context, **kwargs) - - def test_describe_volumes(self): - """Makes sure describe_volumes works and filters results.""" - vol1 = db.volume_create(self.context, {}) - vol2 = db.volume_create(self.context, {}) - result = self.cloud.describe_volumes(self.context) - self.assertEqual(len(result['volumeSet']), 2) - volume_id = ec2utils.id_to_ec2_vol_id(vol2['id']) - result = self.cloud.describe_volumes(self.context, - volume_id=[volume_id]) - self.assertEqual(len(result['volumeSet']), 1) - self.assertEqual( - ec2utils.ec2_id_to_id(result['volumeSet'][0]['volumeId']), - vol2['id']) - db.volume_destroy(self.context, vol1['id']) - db.volume_destroy(self.context, vol2['id']) - - def test_create_volume_from_snapshot(self): - """Makes sure create_volume works when we specify a snapshot.""" - vol = db.volume_create(self.context, {'size': 1}) - snap = db.snapshot_create(self.context, {'volume_id': vol['id'], - 'volume_size': vol['size'], - 'status': "available"}) - snapshot_id = ec2utils.id_to_ec2_snap_id(snap['id']) - - result = self.cloud.create_volume(self.context, - snapshot_id=snapshot_id) - volume_id = result['volumeId'] - result = self.cloud.describe_volumes(self.context) - self.assertEqual(len(result['volumeSet']), 2) - self.assertEqual(result['volumeSet'][1]['volumeId'], volume_id) - - db.volume_destroy(self.context, ec2utils.ec2_id_to_id(volume_id)) - db.snapshot_destroy(self.context, snap['id']) - db.volume_destroy(self.context, vol['id']) - - def test_describe_availability_zones(self): - """Makes sure describe_availability_zones works and filters results.""" - service1 = db.service_create(self.context, {'host': 'host1_zones', - 'binary': "nova-compute", - 'topic': 'compute', - 'report_count': 0, - 'availability_zone': "zone1"}) - service2 = db.service_create(self.context, {'host': 'host2_zones', - 'binary': "nova-compute", - 'topic': 'compute', - 'report_count': 0, - 'availability_zone': "zone2"}) - result = self.cloud.describe_availability_zones(self.context) - self.assertEqual(len(result['availabilityZoneInfo']), 3) - db.service_destroy(self.context, service1['id']) - db.service_destroy(self.context, service2['id']) - - def test_describe_snapshots(self): - """Makes sure describe_snapshots works and filters results.""" - vol = db.volume_create(self.context, {}) - snap1 = db.snapshot_create(self.context, {'volume_id': vol['id']}) - snap2 = db.snapshot_create(self.context, {'volume_id': vol['id']}) - result = self.cloud.describe_snapshots(self.context) - self.assertEqual(len(result['snapshotSet']), 2) - snapshot_id = ec2utils.id_to_ec2_snap_id(snap2['id']) - result = self.cloud.describe_snapshots(self.context, - snapshot_id=[snapshot_id]) - self.assertEqual(len(result['snapshotSet']), 1) - self.assertEqual( - ec2utils.ec2_id_to_id(result['snapshotSet'][0]['snapshotId']), - snap2['id']) - db.snapshot_destroy(self.context, snap1['id']) - db.snapshot_destroy(self.context, snap2['id']) - db.volume_destroy(self.context, vol['id']) - - def test_create_snapshot(self): - """Makes sure create_snapshot works.""" - vol = db.volume_create(self.context, {'status': "available"}) - volume_id = ec2utils.id_to_ec2_vol_id(vol['id']) - - result = self.cloud.create_snapshot(self.context, - volume_id=volume_id) - snapshot_id = result['snapshotId'] - result = self.cloud.describe_snapshots(self.context) - self.assertEqual(len(result['snapshotSet']), 1) - self.assertEqual(result['snapshotSet'][0]['snapshotId'], snapshot_id) - - db.snapshot_destroy(self.context, ec2utils.ec2_id_to_id(snapshot_id)) - db.volume_destroy(self.context, vol['id']) - - def test_delete_snapshot(self): - """Makes sure delete_snapshot works.""" - vol = db.volume_create(self.context, {'status': "available"}) - snap = db.snapshot_create(self.context, {'volume_id': vol['id'], - 'status': "available"}) - snapshot_id = ec2utils.id_to_ec2_snap_id(snap['id']) - - result = self.cloud.delete_snapshot(self.context, - snapshot_id=snapshot_id) - self.assertTrue(result) - - db.volume_destroy(self.context, vol['id']) - - def test_describe_instances(self): - """Makes sure describe_instances works and filters results.""" - inst1 = db.instance_create(self.context, {'reservation_id': 'a', - 'image_ref': 1, - 'host': 'host1'}) - inst2 = db.instance_create(self.context, {'reservation_id': 'a', - 'image_ref': 1, - 'host': 'host2'}) - comp1 = db.service_create(self.context, {'host': 'host1', - 'availability_zone': 'zone1', - 'topic': "compute"}) - comp2 = db.service_create(self.context, {'host': 'host2', - 'availability_zone': 'zone2', - 'topic': "compute"}) - result = self.cloud.describe_instances(self.context) - result = result['reservationSet'][0] - self.assertEqual(len(result['instancesSet']), 2) - instance_id = ec2utils.id_to_ec2_id(inst2['id']) - result = self.cloud.describe_instances(self.context, - instance_id=[instance_id]) - result = result['reservationSet'][0] - self.assertEqual(len(result['instancesSet']), 1) - self.assertEqual(result['instancesSet'][0]['instanceId'], - instance_id) - self.assertEqual(result['instancesSet'][0] - ['placement']['availabilityZone'], 'zone2') - db.instance_destroy(self.context, inst1['id']) - db.instance_destroy(self.context, inst2['id']) - db.service_destroy(self.context, comp1['id']) - db.service_destroy(self.context, comp2['id']) - - def test_describe_instances_deleted(self): - args1 = {'reservation_id': 'a', 'image_ref': 1, 'host': 'host1'} - inst1 = db.instance_create(self.context, args1) - args2 = {'reservation_id': 'b', 'image_ref': 1, 'host': 'host1'} - inst2 = db.instance_create(self.context, args2) - db.instance_destroy(self.context, inst1.id) - result = self.cloud.describe_instances(self.context) - self.assertEqual(len(result['reservationSet']), 1) - result1 = result['reservationSet'][0]['instancesSet'] - self.assertEqual(result1[0]['instanceId'], - ec2utils.id_to_ec2_id(inst2.id)) - - def _block_device_mapping_create(self, instance_id, mappings): - volumes = [] - for bdm in mappings: - db.block_device_mapping_create(self.context, bdm) - if 'volume_id' in bdm: - values = {'id': bdm['volume_id']} - for bdm_key, vol_key in [('snapshot_id', 'snapshot_id'), - ('snapshot_size', 'volume_size'), - ('delete_on_termination', - 'delete_on_termination')]: - if bdm_key in bdm: - values[vol_key] = bdm[bdm_key] - vol = db.volume_create(self.context, values) - db.volume_attached(self.context, vol['id'], - instance_id, bdm['device_name']) - volumes.append(vol) - return volumes - - def _setUpBlockDeviceMapping(self): - inst1 = db.instance_create(self.context, - {'image_ref': 1, - 'root_device_name': '/dev/sdb1'}) - inst2 = db.instance_create(self.context, - {'image_ref': 2, - 'root_device_name': '/dev/sdc1'}) - - instance_id = inst1['id'] - mappings0 = [ - {'instance_id': instance_id, - 'device_name': '/dev/sdb1', - 'snapshot_id': '1', - 'volume_id': '2'}, - {'instance_id': instance_id, - 'device_name': '/dev/sdb2', - 'volume_id': '3', - 'volume_size': 1}, - {'instance_id': instance_id, - 'device_name': '/dev/sdb3', - 'delete_on_termination': True, - 'snapshot_id': '4', - 'volume_id': '5'}, - {'instance_id': instance_id, - 'device_name': '/dev/sdb4', - 'delete_on_termination': False, - 'snapshot_id': '6', - 'volume_id': '7'}, - {'instance_id': instance_id, - 'device_name': '/dev/sdb5', - 'snapshot_id': '8', - 'volume_id': '9', - 'volume_size': 0}, - {'instance_id': instance_id, - 'device_name': '/dev/sdb6', - 'snapshot_id': '10', - 'volume_id': '11', - 'volume_size': 1}, - {'instance_id': instance_id, - 'device_name': '/dev/sdb7', - 'no_device': True}, - {'instance_id': instance_id, - 'device_name': '/dev/sdb8', - 'virtual_name': 'swap'}, - {'instance_id': instance_id, - 'device_name': '/dev/sdb9', - 'virtual_name': 'ephemeral3'}] - - volumes = self._block_device_mapping_create(instance_id, mappings0) - return (inst1, inst2, volumes) - - def _tearDownBlockDeviceMapping(self, inst1, inst2, volumes): - for vol in volumes: - db.volume_destroy(self.context, vol['id']) - for id in (inst1['id'], inst2['id']): - for bdm in db.block_device_mapping_get_all_by_instance( - self.context, id): - db.block_device_mapping_destroy(self.context, bdm['id']) - db.instance_destroy(self.context, inst2['id']) - db.instance_destroy(self.context, inst1['id']) - - _expected_instance_bdm1 = { - 'instanceId': 'i-00000001', - 'rootDeviceName': '/dev/sdb1', - 'rootDeviceType': 'ebs'} - - _expected_block_device_mapping0 = [ - {'deviceName': '/dev/sdb1', - 'ebs': {'status': 'in-use', - 'deleteOnTermination': False, - 'volumeId': 2, - }}, - {'deviceName': '/dev/sdb2', - 'ebs': {'status': 'in-use', - 'deleteOnTermination': False, - 'volumeId': 3, - }}, - {'deviceName': '/dev/sdb3', - 'ebs': {'status': 'in-use', - 'deleteOnTermination': True, - 'volumeId': 5, - }}, - {'deviceName': '/dev/sdb4', - 'ebs': {'status': 'in-use', - 'deleteOnTermination': False, - 'volumeId': 7, - }}, - {'deviceName': '/dev/sdb5', - 'ebs': {'status': 'in-use', - 'deleteOnTermination': False, - 'volumeId': 9, - }}, - {'deviceName': '/dev/sdb6', - 'ebs': {'status': 'in-use', - 'deleteOnTermination': False, - 'volumeId': 11, }}] - # NOTE(yamahata): swap/ephemeral device case isn't supported yet. - - _expected_instance_bdm2 = { - 'instanceId': 'i-00000002', - 'rootDeviceName': '/dev/sdc1', - 'rootDeviceType': 'instance-store'} - - def test_format_instance_bdm(self): - (inst1, inst2, volumes) = self._setUpBlockDeviceMapping() - - result = {} - self.cloud._format_instance_bdm(self.context, inst1['id'], '/dev/sdb1', - result) - self.assertSubDictMatch( - {'rootDeviceType': self._expected_instance_bdm1['rootDeviceType']}, - result) - self._assertEqualBlockDeviceMapping( - self._expected_block_device_mapping0, result['blockDeviceMapping']) - - result = {} - self.cloud._format_instance_bdm(self.context, inst2['id'], '/dev/sdc1', - result) - self.assertSubDictMatch( - {'rootDeviceType': self._expected_instance_bdm2['rootDeviceType']}, - result) - - self._tearDownBlockDeviceMapping(inst1, inst2, volumes) - - def _assertInstance(self, instance_id): - ec2_instance_id = ec2utils.id_to_ec2_id(instance_id) - result = self.cloud.describe_instances(self.context, - instance_id=[ec2_instance_id]) - result = result['reservationSet'][0] - self.assertEqual(len(result['instancesSet']), 1) - result = result['instancesSet'][0] - self.assertEqual(result['instanceId'], ec2_instance_id) - return result - - def _assertEqualBlockDeviceMapping(self, expected, result): - self.assertEqual(len(expected), len(result)) - for x in expected: - found = False - for y in result: - if x['deviceName'] == y['deviceName']: - self.assertSubDictMatch(x, y) - found = True - break - self.assertTrue(found) - - def test_describe_instances_bdm(self): - """Make sure describe_instances works with root_device_name and - block device mappings - """ - (inst1, inst2, volumes) = self._setUpBlockDeviceMapping() - - result = self._assertInstance(inst1['id']) - self.assertSubDictMatch(self._expected_instance_bdm1, result) - self._assertEqualBlockDeviceMapping( - self._expected_block_device_mapping0, result['blockDeviceMapping']) - - result = self._assertInstance(inst2['id']) - self.assertSubDictMatch(self._expected_instance_bdm2, result) - - self._tearDownBlockDeviceMapping(inst1, inst2, volumes) - - def test_describe_images(self): - describe_images = self.cloud.describe_images - - def fake_detail(meh, context): - return [{'id': 1, 'container_format': 'ami', - 'properties': {'kernel_id': 1, 'ramdisk_id': 1, - 'type': 'machine'}}] - - def fake_show_none(meh, context, id): - raise exception.ImageNotFound(image_id='bad_image_id') - - self.stubs.Set(fake._FakeImageService, 'detail', fake_detail) - # list all - result1 = describe_images(self.context) - result1 = result1['imagesSet'][0] - self.assertEqual(result1['imageId'], 'ami-00000001') - # provided a valid image_id - result2 = describe_images(self.context, ['ami-00000001']) - self.assertEqual(1, len(result2['imagesSet'])) - # provide more than 1 valid image_id - result3 = describe_images(self.context, ['ami-00000001', - 'ami-00000002']) - self.assertEqual(2, len(result3['imagesSet'])) - # provide an non-existing image_id - self.stubs.UnsetAll() - self.stubs.Set(fake._FakeImageService, 'show', fake_show_none) - self.stubs.Set(fake._FakeImageService, 'show_by_name', fake_show_none) - self.assertRaises(exception.ImageNotFound, describe_images, - self.context, ['ami-fake']) - - def assertDictListUnorderedMatch(self, L1, L2, key): - self.assertEqual(len(L1), len(L2)) - for d1 in L1: - self.assertTrue(key in d1) - for d2 in L2: - self.assertTrue(key in d2) - if d1[key] == d2[key]: - self.assertDictMatch(d1, d2) - - def _setUpImageSet(self, create_volumes_and_snapshots=False): - mappings1 = [ - {'device': '/dev/sda1', 'virtual': 'root'}, - - {'device': 'sdb0', 'virtual': 'ephemeral0'}, - {'device': 'sdb1', 'virtual': 'ephemeral1'}, - {'device': 'sdb2', 'virtual': 'ephemeral2'}, - {'device': 'sdb3', 'virtual': 'ephemeral3'}, - {'device': 'sdb4', 'virtual': 'ephemeral4'}, - - {'device': 'sdc0', 'virtual': 'swap'}, - {'device': 'sdc1', 'virtual': 'swap'}, - {'device': 'sdc2', 'virtual': 'swap'}, - {'device': 'sdc3', 'virtual': 'swap'}, - {'device': 'sdc4', 'virtual': 'swap'}] - block_device_mapping1 = [ - {'device_name': '/dev/sdb1', 'snapshot_id': 01234567}, - {'device_name': '/dev/sdb2', 'volume_id': 01234567}, - {'device_name': '/dev/sdb3', 'virtual_name': 'ephemeral5'}, - {'device_name': '/dev/sdb4', 'no_device': True}, - - {'device_name': '/dev/sdc1', 'snapshot_id': 12345678}, - {'device_name': '/dev/sdc2', 'volume_id': 12345678}, - {'device_name': '/dev/sdc3', 'virtual_name': 'ephemeral6'}, - {'device_name': '/dev/sdc4', 'no_device': True}] - image1 = { - 'id': 1, - 'properties': { - 'kernel_id': 1, - 'type': 'machine', - 'image_state': 'available', - 'mappings': mappings1, - 'block_device_mapping': block_device_mapping1, - } - } - - mappings2 = [{'device': '/dev/sda1', 'virtual': 'root'}] - block_device_mapping2 = [{'device_name': '/dev/sdb1', - 'snapshot_id': 01234567}] - image2 = { - 'id': 2, - 'properties': { - 'kernel_id': 2, - 'type': 'machine', - 'root_device_name': '/dev/sdb1', - 'mappings': mappings2, - 'block_device_mapping': block_device_mapping2}} - - def fake_show(meh, context, image_id): - for i in [image1, image2]: - if i['id'] == image_id: - return i - raise exception.ImageNotFound(image_id=image_id) - - def fake_detail(meh, context): - return [image1, image2] - - self.stubs.Set(fake._FakeImageService, 'show', fake_show) - self.stubs.Set(fake._FakeImageService, 'detail', fake_detail) - - volumes = [] - snapshots = [] - if create_volumes_and_snapshots: - for bdm in block_device_mapping1: - if 'volume_id' in bdm: - vol = self._volume_create(bdm['volume_id']) - volumes.append(vol['id']) - if 'snapshot_id' in bdm: - snap = db.snapshot_create(self.context, - {'id': bdm['snapshot_id'], - 'volume_id': 76543210, - 'status': "available", - 'volume_size': 1}) - snapshots.append(snap['id']) - return (volumes, snapshots) - - def _assertImageSet(self, result, root_device_type, root_device_name): - self.assertEqual(1, len(result['imagesSet'])) - result = result['imagesSet'][0] - self.assertTrue('rootDeviceType' in result) - self.assertEqual(result['rootDeviceType'], root_device_type) - self.assertTrue('rootDeviceName' in result) - self.assertEqual(result['rootDeviceName'], root_device_name) - self.assertTrue('blockDeviceMapping' in result) - - return result - - _expected_root_device_name1 = '/dev/sda1' - # NOTE(yamahata): noDevice doesn't make sense when returning mapping - # It makes sense only when user overriding existing - # mapping. - _expected_bdms1 = [ - {'deviceName': '/dev/sdb0', 'virtualName': 'ephemeral0'}, - {'deviceName': '/dev/sdb1', 'ebs': {'snapshotId': - 'snap-00053977'}}, - {'deviceName': '/dev/sdb2', 'ebs': {'snapshotId': - 'vol-00053977'}}, - {'deviceName': '/dev/sdb3', 'virtualName': 'ephemeral5'}, - # {'deviceName': '/dev/sdb4', 'noDevice': True}, - - {'deviceName': '/dev/sdc0', 'virtualName': 'swap'}, - {'deviceName': '/dev/sdc1', 'ebs': {'snapshotId': - 'snap-00bc614e'}}, - {'deviceName': '/dev/sdc2', 'ebs': {'snapshotId': - 'vol-00bc614e'}}, - {'deviceName': '/dev/sdc3', 'virtualName': 'ephemeral6'}, - # {'deviceName': '/dev/sdc4', 'noDevice': True} - ] - - _expected_root_device_name2 = '/dev/sdb1' - _expected_bdms2 = [{'deviceName': '/dev/sdb1', - 'ebs': {'snapshotId': 'snap-00053977'}}] - - # NOTE(yamahata): - # InstanceBlockDeviceMappingItemType - # rootDeviceType - # rootDeviceName - # blockDeviceMapping - # deviceName - # virtualName - # ebs - # snapshotId - # volumeSize - # deleteOnTermination - # noDevice - def test_describe_image_mapping(self): - """test for rootDeviceName and blockDeiceMapping""" - describe_images = self.cloud.describe_images - self._setUpImageSet() - - result = describe_images(self.context, ['ami-00000001']) - result = self._assertImageSet(result, 'instance-store', - self._expected_root_device_name1) - - self.assertDictListUnorderedMatch(result['blockDeviceMapping'], - self._expected_bdms1, 'deviceName') - - result = describe_images(self.context, ['ami-00000002']) - result = self._assertImageSet(result, 'ebs', - self._expected_root_device_name2) - - self.assertDictListUnorderedMatch(result['blockDeviceMapping'], - self._expected_bdms2, 'deviceName') - - self.stubs.UnsetAll() - - def test_describe_image_attribute(self): - describe_image_attribute = self.cloud.describe_image_attribute - - def fake_show(meh, context, id): - return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1, - 'type': 'machine'}, 'container_format': 'ami', - 'is_public': True} - - self.stubs.Set(fake._FakeImageService, 'show', fake_show) - self.stubs.Set(fake._FakeImageService, 'show_by_name', fake_show) - result = describe_image_attribute(self.context, 'ami-00000001', - 'launchPermission') - self.assertEqual([{'group': 'all'}], result['launchPermission']) - - def test_describe_image_attribute_root_device_name(self): - describe_image_attribute = self.cloud.describe_image_attribute - self._setUpImageSet() - - result = describe_image_attribute(self.context, 'ami-00000001', - 'rootDeviceName') - self.assertEqual(result['rootDeviceName'], - self._expected_root_device_name1) - result = describe_image_attribute(self.context, 'ami-00000002', - 'rootDeviceName') - self.assertEqual(result['rootDeviceName'], - self._expected_root_device_name2) - - def test_describe_image_attribute_block_device_mapping(self): - describe_image_attribute = self.cloud.describe_image_attribute - self._setUpImageSet() - - result = describe_image_attribute(self.context, 'ami-00000001', - 'blockDeviceMapping') - self.assertDictListUnorderedMatch(result['blockDeviceMapping'], - self._expected_bdms1, 'deviceName') - result = describe_image_attribute(self.context, 'ami-00000002', - 'blockDeviceMapping') - self.assertDictListUnorderedMatch(result['blockDeviceMapping'], - self._expected_bdms2, 'deviceName') - - 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 fake_metadata - - def fake_update(meh, context, image_id, metadata, data=None): - 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) - self.stubs.Set(fake._FakeImageService, 'update', fake_update) - result = modify_image_attribute(self.context, 'ami-00000001', - 'launchPermission', 'add', - user_group=['all']) - self.assertEqual(True, result['is_public']) - - def test_deregister_image(self): - deregister_image = self.cloud.deregister_image - - def fake_delete(self, context, id): - return None - - self.stubs.Set(fake._FakeImageService, 'delete', fake_delete) - # valid image - result = deregister_image(self.context, 'ami-00000001') - self.assertEqual(result['imageId'], 'ami-00000001') - # invalid image - self.stubs.UnsetAll() - - def fake_detail_empty(self, context): - return [] - - self.stubs.Set(fake._FakeImageService, 'detail', fake_detail_empty) - self.assertRaises(exception.ImageNotFound, deregister_image, - self.context, 'ami-bad001') - - def test_deregister_image_wrong_container_type(self): - deregister_image = self.cloud.deregister_image - - def fake_delete(self, context, id): - return None - - self.stubs.Set(fake._FakeImageService, 'delete', fake_delete) - self.assertRaises(exception.NotFound, deregister_image, self.context, - 'aki-00000001') - - def _run_instance(self, **kwargs): - rv = self.cloud.run_instances(self.context, **kwargs) - instance_id = rv['instancesSet'][0]['instanceId'] - return instance_id - - def _run_instance_wait(self, **kwargs): - ec2_instance_id = self._run_instance(**kwargs) - self._wait_for_running(ec2_instance_id) - return ec2_instance_id - - def test_console_output(self): - instance_id = self._run_instance( - image_id='ami-1', - instance_type=FLAGS.default_instance_type, - max_count=1) - output = self.cloud.get_console_output(context=self.context, - instance_id=[instance_id]) - self.assertEquals(b64decode(output['output']), 'FAKE CONSOLE?OUTPUT') - # TODO(soren): We need this until we can stop polling in the rpc code - # for unit tests. - rv = self.cloud.terminate_instances(self.context, [instance_id]) - - def test_ajax_console(self): - instance_id = self._run_instance(image_id='ami-1') - output = self.cloud.get_ajax_console(context=self.context, - instance_id=[instance_id]) - self.assertEquals(output['url'], - '%s/?token=FAKETOKEN' % FLAGS.ajax_console_proxy_url) - # TODO(soren): We need this until we can stop polling in the rpc code - # for unit tests. - rv = self.cloud.terminate_instances(self.context, [instance_id]) - - def test_key_generation(self): - result = self._create_key('test') - private_key = result['private_key'] - key = RSA.load_key_string(private_key, callback=lambda: None) - bio = BIO.MemoryBuffer() - public_key = db.key_pair_get(self.context, - self.context.user_id, - 'test')['public_key'] - key.save_pub_key_bio(bio) - converted = crypto.ssl_pub_to_ssh_pub(bio.read()) - # assert key fields are equal - self.assertEqual(public_key.split(" ")[1].strip(), - converted.split(" ")[1].strip()) - - def test_describe_key_pairs(self): - self._create_key('test1') - self._create_key('test2') - result = self.cloud.describe_key_pairs(self.context) - keys = result["keySet"] - self.assertTrue(filter(lambda k: k['keyName'] == 'test1', keys)) - self.assertTrue(filter(lambda k: k['keyName'] == 'test2', keys)) - - def test_import_public_key(self): - # test when user provides all values - result1 = self.cloud.import_public_key(self.context, - 'testimportkey1', - 'mytestpubkey', - 'mytestfprint') - self.assertTrue(result1) - keydata = db.key_pair_get(self.context, - self.context.user_id, - 'testimportkey1') - self.assertEqual('mytestpubkey', keydata['public_key']) - self.assertEqual('mytestfprint', keydata['fingerprint']) - # test when user omits fingerprint - pubkey_path = os.path.join(os.path.dirname(__file__), 'public_key') - f = open(pubkey_path + '/dummy.pub', 'r') - dummypub = f.readline().rstrip() - f.close - f = open(pubkey_path + '/dummy.fingerprint', 'r') - dummyfprint = f.readline().rstrip() - f.close - result2 = self.cloud.import_public_key(self.context, - 'testimportkey2', - dummypub) - self.assertTrue(result2) - keydata = db.key_pair_get(self.context, - self.context.user_id, - 'testimportkey2') - self.assertEqual(dummypub, keydata['public_key']) - self.assertEqual(dummyfprint, keydata['fingerprint']) - - def test_delete_key_pair(self): - self._create_key('test') - self.cloud.delete_key_pair(self.context, 'test') - - def test_run_instances(self): - kwargs = {'image_id': FLAGS.default_image, - 'instance_type': FLAGS.default_instance_type, - 'max_count': 1} - run_instances = self.cloud.run_instances - result = run_instances(self.context, **kwargs) - instance = result['instancesSet'][0] - self.assertEqual(instance['imageId'], 'ami-00000001') - self.assertEqual(instance['displayName'], 'Server 1') - self.assertEqual(instance['instanceId'], 'i-00000001') - self.assertEqual(instance['instanceState']['name'], 'running') - self.assertEqual(instance['instanceType'], 'm1.small') - - def test_run_instances_image_state_none(self): - kwargs = {'image_id': FLAGS.default_image, - 'instance_type': FLAGS.default_instance_type, - 'max_count': 1} - run_instances = self.cloud.run_instances - - def fake_show_no_state(self, context, id): - return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1, - 'type': 'machine'}, 'container_format': 'ami'} - - self.stubs.UnsetAll() - self.stubs.Set(fake._FakeImageService, 'show', fake_show_no_state) - self.assertRaises(exception.ApiError, run_instances, - self.context, **kwargs) - - def test_run_instances_image_state_invalid(self): - kwargs = {'image_id': FLAGS.default_image, - 'instance_type': FLAGS.default_instance_type, - 'max_count': 1} - run_instances = self.cloud.run_instances - - def fake_show_decrypt(self, context, id): - return {'id': 1, 'container_format': 'ami', - 'properties': {'kernel_id': 1, 'ramdisk_id': 1, - 'type': 'machine', 'image_state': 'decrypting'}} - - self.stubs.UnsetAll() - self.stubs.Set(fake._FakeImageService, 'show', fake_show_decrypt) - self.assertRaises(exception.ApiError, run_instances, - self.context, **kwargs) - - def test_run_instances_image_status_active(self): - kwargs = {'image_id': FLAGS.default_image, - 'instance_type': FLAGS.default_instance_type, - 'max_count': 1} - run_instances = self.cloud.run_instances - - def fake_show_stat_active(self, context, id): - return {'id': 1, 'container_format': 'ami', - 'properties': {'kernel_id': 1, 'ramdisk_id': 1, - 'type': 'machine'}, 'status': 'active'} - - self.stubs.Set(fake._FakeImageService, 'show', fake_show_stat_active) - - result = run_instances(self.context, **kwargs) - self.assertEqual(len(result['instancesSet']), 1) - - def test_terminate_instances(self): - inst1 = db.instance_create(self.context, {'reservation_id': 'a', - 'image_ref': 1, - 'host': 'host1'}) - terminate_instances = self.cloud.terminate_instances - # valid instance_id - result = terminate_instances(self.context, ['i-00000001']) - self.assertTrue(result) - # non-existing instance_id - self.assertRaises(exception.InstanceNotFound, terminate_instances, - self.context, ['i-2']) - db.instance_destroy(self.context, inst1['id']) - - def test_update_of_instance_display_fields(self): - inst = db.instance_create(self.context, {}) - ec2_id = ec2utils.id_to_ec2_id(inst['id']) - self.cloud.update_instance(self.context, ec2_id, - display_name='c00l 1m4g3') - inst = db.instance_get(self.context, inst['id']) - self.assertEqual('c00l 1m4g3', inst['display_name']) - db.instance_destroy(self.context, inst['id']) - - def test_update_of_instance_wont_update_private_fields(self): - inst = db.instance_create(self.context, {}) - host = inst['host'] - ec2_id = ec2utils.id_to_ec2_id(inst['id']) - self.cloud.update_instance(self.context, ec2_id, - display_name='c00l 1m4g3', - host='otherhost') - inst = db.instance_get(self.context, inst['id']) - self.assertEqual(host, inst['host']) - db.instance_destroy(self.context, inst['id']) - - def test_update_of_volume_display_fields(self): - vol = db.volume_create(self.context, {}) - self.cloud.update_volume(self.context, - ec2utils.id_to_ec2_vol_id(vol['id']), - display_name='c00l v0lum3') - vol = db.volume_get(self.context, vol['id']) - self.assertEqual('c00l v0lum3', vol['display_name']) - db.volume_destroy(self.context, vol['id']) - - def test_update_of_volume_wont_update_private_fields(self): - vol = db.volume_create(self.context, {}) - self.cloud.update_volume(self.context, - ec2utils.id_to_ec2_vol_id(vol['id']), - mountpoint='/not/here') - vol = db.volume_get(self.context, vol['id']) - self.assertEqual(None, vol['mountpoint']) - db.volume_destroy(self.context, vol['id']) - - def _restart_compute_service(self, periodic_interval=None): - """restart compute service. NOTE: fake driver forgets all instances.""" - self.compute.kill() - if periodic_interval: - self.compute = self.start_service( - 'compute', periodic_interval=periodic_interval) - else: - self.compute = self.start_service('compute') - - def _wait_for_state(self, ctxt, instance_id, predicate): - """Wait for a stopped instance to be a given state""" - id = ec2utils.ec2_id_to_id(instance_id) - while True: - info = self.cloud.compute_api.get(context=ctxt, instance_id=id) - LOG.debug(info) - if predicate(info): - break - greenthread.sleep(1) - - def _wait_for_running(self, instance_id): - def is_running(info): - vm_state = info["vm_state"] - task_state = info["task_state"] - return vm_state == vm_states.ACTIVE and task_state == None - self._wait_for_state(self.context, instance_id, is_running) - - def _wait_for_stopped(self, instance_id): - def is_stopped(info): - vm_state = info["vm_state"] - task_state = info["task_state"] - return vm_state == vm_states.STOPPED and task_state == None - self._wait_for_state(self.context, instance_id, is_stopped) - - def _wait_for_terminate(self, instance_id): - def is_deleted(info): - return info['deleted'] - elevated = self.context.elevated(read_deleted=True) - self._wait_for_state(elevated, instance_id, is_deleted) - - def test_stop_start_instance(self): - """Makes sure stop/start instance works""" - # enforce periodic tasks run in short time to avoid wait for 60s. - self._restart_compute_service(periodic_interval=0.3) - - kwargs = {'image_id': 'ami-1', - 'instance_type': FLAGS.default_instance_type, - 'max_count': 1, } - instance_id = self._run_instance_wait(**kwargs) - - # a running instance can't be started. It is just ignored. - result = self.cloud.start_instances(self.context, [instance_id]) - greenthread.sleep(0.3) - self.assertTrue(result) - - result = self.cloud.stop_instances(self.context, [instance_id]) - greenthread.sleep(0.3) - self.assertTrue(result) - self._wait_for_stopped(instance_id) - - result = self.cloud.start_instances(self.context, [instance_id]) - greenthread.sleep(0.3) - self.assertTrue(result) - self._wait_for_running(instance_id) - - result = self.cloud.stop_instances(self.context, [instance_id]) - greenthread.sleep(0.3) - self.assertTrue(result) - self._wait_for_stopped(instance_id) - - result = self.cloud.terminate_instances(self.context, [instance_id]) - greenthread.sleep(0.3) - self.assertTrue(result) - - self._restart_compute_service() - - def _volume_create(self, volume_id=None): - kwargs = {'status': 'available', - 'host': self.volume.host, - 'size': 1, - 'attach_status': 'detached', } - if volume_id: - kwargs['id'] = volume_id - return db.volume_create(self.context, kwargs) - - def _assert_volume_attached(self, vol, instance_id, mountpoint): - self.assertEqual(vol['instance_id'], instance_id) - self.assertEqual(vol['mountpoint'], mountpoint) - self.assertEqual(vol['status'], "in-use") - self.assertEqual(vol['attach_status'], "attached") - - def _assert_volume_detached(self, vol): - self.assertEqual(vol['instance_id'], None) - self.assertEqual(vol['mountpoint'], None) - self.assertEqual(vol['status'], "available") - self.assertEqual(vol['attach_status'], "detached") - - def test_stop_start_with_volume(self): - """Make sure run instance with block device mapping works""" - - # enforce periodic tasks run in short time to avoid wait for 60s. - self._restart_compute_service(periodic_interval=0.3) - - vol1 = self._volume_create() - vol2 = self._volume_create() - kwargs = {'image_id': 'ami-1', - 'instance_type': FLAGS.default_instance_type, - 'max_count': 1, - 'block_device_mapping': [{'device_name': '/dev/vdb', - 'volume_id': vol1['id'], - 'delete_on_termination': False}, - {'device_name': '/dev/vdc', - 'volume_id': vol2['id'], - 'delete_on_termination': True}, - ]} - ec2_instance_id = self._run_instance_wait(**kwargs) - instance_id = ec2utils.ec2_id_to_id(ec2_instance_id) - - vols = db.volume_get_all_by_instance(self.context, instance_id) - self.assertEqual(len(vols), 2) - for vol in vols: - self.assertTrue(vol['id'] == vol1['id'] or vol['id'] == vol2['id']) - - vol = db.volume_get(self.context, vol1['id']) - self._assert_volume_attached(vol, instance_id, '/dev/vdb') - - vol = db.volume_get(self.context, vol2['id']) - self._assert_volume_attached(vol, instance_id, '/dev/vdc') - - result = self.cloud.stop_instances(self.context, [ec2_instance_id]) - self.assertTrue(result) - self._wait_for_stopped(ec2_instance_id) - - vol = db.volume_get(self.context, vol1['id']) - self._assert_volume_detached(vol) - vol = db.volume_get(self.context, vol2['id']) - self._assert_volume_detached(vol) - - self.cloud.start_instances(self.context, [ec2_instance_id]) - self._wait_for_running(ec2_instance_id) - vols = db.volume_get_all_by_instance(self.context, instance_id) - self.assertEqual(len(vols), 2) - for vol in vols: - self.assertTrue(vol['id'] == vol1['id'] or vol['id'] == vol2['id']) - self.assertTrue(vol['mountpoint'] == '/dev/vdb' or - vol['mountpoint'] == '/dev/vdc') - self.assertEqual(vol['instance_id'], instance_id) - self.assertEqual(vol['status'], "in-use") - self.assertEqual(vol['attach_status'], "attached") - - self.cloud.terminate_instances(self.context, [ec2_instance_id]) - greenthread.sleep(0.3) - - admin_ctxt = context.get_admin_context(read_deleted=False) - vol = db.volume_get(admin_ctxt, vol1['id']) - self.assertFalse(vol['deleted']) - db.volume_destroy(self.context, vol1['id']) - - greenthread.sleep(0.3) - admin_ctxt = context.get_admin_context(read_deleted=True) - vol = db.volume_get(admin_ctxt, vol2['id']) - self.assertTrue(vol['deleted']) - - self._restart_compute_service() - - def test_stop_with_attached_volume(self): - """Make sure attach info is reflected to block device mapping""" - # enforce periodic tasks run in short time to avoid wait for 60s. - self._restart_compute_service(periodic_interval=0.3) - - vol1 = self._volume_create() - vol2 = self._volume_create() - kwargs = {'image_id': 'ami-1', - 'instance_type': FLAGS.default_instance_type, - 'max_count': 1, - 'block_device_mapping': [{'device_name': '/dev/vdb', - 'volume_id': vol1['id'], - 'delete_on_termination': True}]} - ec2_instance_id = self._run_instance_wait(**kwargs) - instance_id = ec2utils.ec2_id_to_id(ec2_instance_id) - - vols = db.volume_get_all_by_instance(self.context, instance_id) - self.assertEqual(len(vols), 1) - for vol in vols: - self.assertEqual(vol['id'], vol1['id']) - self._assert_volume_attached(vol, instance_id, '/dev/vdb') - - vol = db.volume_get(self.context, vol2['id']) - self._assert_volume_detached(vol) - - self.cloud.compute_api.attach_volume(self.context, - instance_id=instance_id, - volume_id=vol2['id'], - device='/dev/vdc') - greenthread.sleep(0.3) - vol = db.volume_get(self.context, vol2['id']) - self._assert_volume_attached(vol, instance_id, '/dev/vdc') - - self.cloud.compute_api.detach_volume(self.context, - volume_id=vol1['id']) - greenthread.sleep(0.3) - vol = db.volume_get(self.context, vol1['id']) - self._assert_volume_detached(vol) - - result = self.cloud.stop_instances(self.context, [ec2_instance_id]) - self.assertTrue(result) - self._wait_for_stopped(ec2_instance_id) - - for vol_id in (vol1['id'], vol2['id']): - vol = db.volume_get(self.context, vol_id) - self._assert_volume_detached(vol) - - self.cloud.start_instances(self.context, [ec2_instance_id]) - self._wait_for_running(ec2_instance_id) - vols = db.volume_get_all_by_instance(self.context, instance_id) - self.assertEqual(len(vols), 1) - for vol in vols: - self.assertEqual(vol['id'], vol2['id']) - self._assert_volume_attached(vol, instance_id, '/dev/vdc') - - vol = db.volume_get(self.context, vol1['id']) - self._assert_volume_detached(vol) - - self.cloud.terminate_instances(self.context, [ec2_instance_id]) - greenthread.sleep(0.3) - - for vol_id in (vol1['id'], vol2['id']): - vol = db.volume_get(self.context, vol_id) - self.assertEqual(vol['id'], vol_id) - self._assert_volume_detached(vol) - db.volume_destroy(self.context, vol_id) - - self._restart_compute_service() - - def _create_snapshot(self, ec2_volume_id): - result = self.cloud.create_snapshot(self.context, - volume_id=ec2_volume_id) - greenthread.sleep(0.3) - return result['snapshotId'] - - def test_run_with_snapshot(self): - """Makes sure run/stop/start instance with snapshot works.""" - vol = self._volume_create() - ec2_volume_id = ec2utils.id_to_ec2_vol_id(vol['id']) - - ec2_snapshot1_id = self._create_snapshot(ec2_volume_id) - snapshot1_id = ec2utils.ec2_id_to_id(ec2_snapshot1_id) - ec2_snapshot2_id = self._create_snapshot(ec2_volume_id) - snapshot2_id = ec2utils.ec2_id_to_id(ec2_snapshot2_id) - - kwargs = {'image_id': 'ami-1', - 'instance_type': FLAGS.default_instance_type, - 'max_count': 1, - 'block_device_mapping': [{'device_name': '/dev/vdb', - 'snapshot_id': snapshot1_id, - 'delete_on_termination': False, }, - {'device_name': '/dev/vdc', - 'snapshot_id': snapshot2_id, - 'delete_on_termination': True}]} - ec2_instance_id = self._run_instance_wait(**kwargs) - instance_id = ec2utils.ec2_id_to_id(ec2_instance_id) - - vols = db.volume_get_all_by_instance(self.context, instance_id) - self.assertEqual(len(vols), 2) - vol1_id = None - vol2_id = None - for vol in vols: - snapshot_id = vol['snapshot_id'] - if snapshot_id == snapshot1_id: - vol1_id = vol['id'] - mountpoint = '/dev/vdb' - elif snapshot_id == snapshot2_id: - vol2_id = vol['id'] - mountpoint = '/dev/vdc' - else: - self.fail() - - self._assert_volume_attached(vol, instance_id, mountpoint) - - self.assertTrue(vol1_id) - self.assertTrue(vol2_id) - - self.cloud.terminate_instances(self.context, [ec2_instance_id]) - greenthread.sleep(0.3) - self._wait_for_terminate(ec2_instance_id) - - greenthread.sleep(0.3) - admin_ctxt = context.get_admin_context(read_deleted=False) - vol = db.volume_get(admin_ctxt, vol1_id) - self._assert_volume_detached(vol) - self.assertFalse(vol['deleted']) - db.volume_destroy(self.context, vol1_id) - - greenthread.sleep(0.3) - admin_ctxt = context.get_admin_context(read_deleted=True) - vol = db.volume_get(admin_ctxt, vol2_id) - self.assertTrue(vol['deleted']) - - for snapshot_id in (ec2_snapshot1_id, ec2_snapshot2_id): - self.cloud.delete_snapshot(self.context, snapshot_id) - greenthread.sleep(0.3) - db.volume_destroy(self.context, vol['id']) - - def test_create_image(self): - """Make sure that CreateImage works""" - # enforce periodic tasks run in short time to avoid wait for 60s. - self._restart_compute_service(periodic_interval=0.3) - - (volumes, snapshots) = self._setUpImageSet( - create_volumes_and_snapshots=True) - - kwargs = {'image_id': 'ami-1', - 'instance_type': FLAGS.default_instance_type, - 'max_count': 1} - ec2_instance_id = self._run_instance_wait(**kwargs) - - # TODO(yamahata): s3._s3_create() can't be tested easily by unit test - # as there is no unit test for s3.create() - ## result = self.cloud.create_image(self.context, ec2_instance_id, - ## no_reboot=True) - ## ec2_image_id = result['imageId'] - ## created_image = self.cloud.describe_images(self.context, - ## [ec2_image_id]) - - self.cloud.terminate_instances(self.context, [ec2_instance_id]) - for vol in volumes: - db.volume_destroy(self.context, vol) - for snap in snapshots: - db.snapshot_destroy(self.context, snap) - # 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'}], - 'vm_state': vm_states.STOPPED, - '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': 'stopped'}) - 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'}) -- cgit From a5c654884abee43760f4b43368f352272ae090dd Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Mon, 12 Sep 2011 18:23:46 -0400 Subject: fixing import --- nova/tests/test_direct.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/tests') diff --git a/nova/tests/test_direct.py b/nova/tests/test_direct.py index 4ed0c2aa5..8d856dc4b 100644 --- a/nova/tests/test_direct.py +++ b/nova/tests/test_direct.py @@ -30,7 +30,7 @@ from nova import test from nova import volume from nova import utils from nova.api import direct -from nova.tests import test_cloud +from nova.tests.api.ec2 import test_cloud class ArbitraryObject(object): -- cgit From 837f611af4467c716a0585bb8f38345ceef32921 Mon Sep 17 00:00:00 2001 From: Naveed Massjouni Date: Mon, 12 Sep 2011 19:13:18 -0400 Subject: Made tests version version links more robust --- nova/tests/api/openstack/test_versions.py | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_versions.py b/nova/tests/api/openstack/test_versions.py index 686752509..0ad26135e 100644 --- a/nova/tests/api/openstack/test_versions.py +++ b/nova/tests/api/openstack/test_versions.py @@ -309,9 +309,8 @@ class VersionsTest(test.TestCase): self.assertEqual(f.feed.author, 'Rackspace') self.assertEqual(f.feed.author_detail.href, 'http://www.rackspace.com/') - self.assertEqual(f.feed.links, [{'href': 'http://localhost/v1.0/', - 'type': 'application/atom+xml', - 'rel': 'self'}]) + self.assertEqual(f.feed.links[0]['href'], 'http://localhost/v1.0/') + self.assertEqual(f.feed.links[0]['rel'], 'self') self.assertEqual(len(f.entries), 1) entry = f.entries[0] @@ -354,9 +353,8 @@ class VersionsTest(test.TestCase): self.assertEqual(f.feed.author, 'Rackspace') self.assertEqual(f.feed.author_detail.href, 'http://www.rackspace.com/') - self.assertEqual(f.feed.links, [{'href': 'http://localhost/v1.1/', - 'type': 'application/atom+xml', - 'rel': 'self'}]) + self.assertEqual(f.feed.links[0]['href'], 'http://localhost/v1.1/') + self.assertEqual(f.feed.links[0]['rel'], 'self') self.assertEqual(len(f.entries), 1) entry = f.entries[0] @@ -399,9 +397,8 @@ class VersionsTest(test.TestCase): self.assertEqual(f.feed.author, 'Rackspace') self.assertEqual(f.feed.author_detail.href, 'http://www.rackspace.com/') - self.assertEqual(f.feed.links, [{'href': 'http://localhost/', - 'type': 'application/atom+xml', - 'rel': 'self'}]) + self.assertEqual(f.feed.links[0]['href'], 'http://localhost/') + self.assertEqual(f.feed.links[0]['rel'], 'self') self.assertEqual(len(f.entries), 2) entry = f.entries[0] @@ -790,9 +787,9 @@ class VersionsSerializerTests(test.TestCase): self.assertEqual(f.feed.author, 'Rackspace') self.assertEqual(f.feed.author_detail.href, 'http://www.rackspace.com/') - self.assertEqual(f.feed.links, [{'href': 'http://test/', - 'type': 'application/atom+xml', - 'rel': 'self'}]) + self.assertEqual(f.feed.links[0]['href'], 'http://test/') + self.assertEqual(f.feed.links[0]['rel'], 'self') + self.assertEqual(len(f.entries), 1) entry = f.entries[0] self.assertEqual(entry.id, 'http://test/2.9.8') @@ -853,9 +850,9 @@ class VersionsSerializerTests(test.TestCase): self.assertEqual(f.feed.author, 'Rackspace') self.assertEqual(f.feed.author_detail.href, 'http://www.rackspace.com/') - self.assertEqual(f.feed.links, [{'href': 'http://localhost/v1.1/', - 'type': 'application/atom+xml', - 'rel': 'self'}]) + self.assertEqual(f.feed.links[0]['href'], 'http://localhost/v1.1/') + self.assertEqual(f.feed.links[0]['rel'], 'self') + self.assertEqual(len(f.entries), 1) entry = f.entries[0] self.assertEqual(entry.id, 'http://localhost/v1.1/') -- cgit From 4c2f8b561390358cbd1c8dbfbc7e4d8370b2b84e Mon Sep 17 00:00:00 2001 From: Naveed Massjouni Date: Tue, 13 Sep 2011 02:45:11 -0400 Subject: Same as last time. --- nova/tests/api/openstack/test_versions.py | 109 +++++++++++++----------------- 1 file changed, 46 insertions(+), 63 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_versions.py b/nova/tests/api/openstack/test_versions.py index 0ad26135e..0077cbe79 100644 --- a/nova/tests/api/openstack/test_versions.py +++ b/nova/tests/api/openstack/test_versions.py @@ -320,24 +320,19 @@ class VersionsTest(test.TestCase): self.assertEqual(len(entry.content), 1) self.assertEqual(entry.content[0].value, 'Version v1.0 DEPRECATED (2011-01-21T11:33:21Z)') - self.assertEqual(entry.links, [ - { - 'href': 'http://localhost/v1.0/', - 'type': 'application/atom+xml', - 'rel': 'self' - }, - { - 'href': 'http://docs.rackspacecloud.com/servers/api/v1.0/'\ - 'cs-devguide-20110125.pdf', - 'type': 'application/pdf', - 'rel': 'describedby' - }, - { - 'href': 'http://docs.rackspacecloud.com/servers/api/v1.0/'\ - 'application.wadl', - 'type': 'application/vnd.sun.wadl+xml', - 'rel': 'describedby' - }]) + self.assertEqual(len(entry.links), 3) + self.assertEqual(entry.links[0]['href'], 'http://localhost/v1.0/') + self.assertEqual(entry.links[0]['rel'], 'self') + self.assertEqual(entry.links[1], { + 'href': 'http://docs.rackspacecloud.com/servers/api/v1.0/'\ + 'cs-devguide-20110125.pdf', + 'type': 'application/pdf', + 'rel': 'describedby'}) + self.assertEqual(entry.links[2], { + 'href': 'http://docs.rackspacecloud.com/servers/api/v1.0/'\ + 'application.wadl', + 'type': 'application/vnd.sun.wadl+xml', + 'rel': 'describedby'}) def test_get_version_1_1_detail_atom(self): req = webob.Request.blank('/v1.1/') @@ -364,24 +359,19 @@ class VersionsTest(test.TestCase): self.assertEqual(len(entry.content), 1) self.assertEqual(entry.content[0].value, 'Version v1.1 CURRENT (2011-01-21T11:33:21Z)') - self.assertEqual(entry.links, [ - { - 'href': 'http://localhost/v1.1/', - 'type': 'application/atom+xml', - 'rel': 'self' - }, - { - 'href': 'http://docs.rackspacecloud.com/servers/api/v1.1/'\ - 'cs-devguide-20110125.pdf', - 'type': 'application/pdf', - 'rel': 'describedby' - }, - { - 'href': 'http://docs.rackspacecloud.com/servers/api/v1.1/'\ - 'application.wadl', - 'type': 'application/vnd.sun.wadl+xml', - 'rel': 'describedby' - }]) + self.assertEqual(len(entry.links), 3) + self.assertEqual(entry.links[0]['href'], 'http://localhost/v1.1/') + self.assertEqual(entry.links[0]['rel'], 'self') + self.assertEqual(entry.links[1], { + 'href': 'http://docs.rackspacecloud.com/servers/api/v1.1/'\ + 'cs-devguide-20110125.pdf', + 'type': 'application/pdf', + 'rel': 'describedby'}) + self.assertEqual(entry.links[2], { + 'href': 'http://docs.rackspacecloud.com/servers/api/v1.1/'\ + 'application.wadl', + 'type': 'application/vnd.sun.wadl+xml', + 'rel': 'describedby'}) def test_get_version_list_atom(self): req = webob.Request.blank('/') @@ -408,10 +398,9 @@ class VersionsTest(test.TestCase): self.assertEqual(len(entry.content), 1) self.assertEqual(entry.content[0].value, 'Version v1.0 DEPRECATED (2011-01-21T11:33:21Z)') - self.assertEqual(entry.links, [{ - 'href': 'http://localhost/v1.0/', - 'type': 'application/atom+xml', - 'rel': 'self'}]) + self.assertEqual(len(entry.links), 1) + self.assertEqual(entry.links[0]['href'], 'http://localhost/v1.0/') + self.assertEqual(entry.links[0]['rel'], 'self') entry = f.entries[1] self.assertEqual(entry.id, 'http://localhost/v1.1/') self.assertEqual(entry.title, 'Version v1.1') @@ -798,10 +787,9 @@ class VersionsSerializerTests(test.TestCase): self.assertEqual(len(entry.content), 1) self.assertEqual(entry.content[0].value, 'Version 2.9.8 CURRENT (2011-07-20T11:40:00Z)') - self.assertEqual(entry.links, [{ - 'href': 'http://test/2.9.8', - 'type': 'application/atom+xml', - 'rel': 'self'}]) + self.assertEqual(len(entry.links), 1) + self.assertEqual(entry.links[0]['href'], 'http://test/2.9.8') + self.assertEqual(entry.links[0]['rel'], 'self') def test_version_detail_atom_serializer(self): versions_data = { @@ -861,22 +849,17 @@ class VersionsSerializerTests(test.TestCase): self.assertEqual(len(entry.content), 1) self.assertEqual(entry.content[0].value, 'Version v1.1 CURRENT (2011-01-21T11:33:21Z)') - self.assertEqual(entry.links, [ - { - 'rel': 'self', - 'type': 'application/atom+xml', - 'href': 'http://localhost/v1.1/', - }, - { - 'rel': 'describedby', - 'type': 'application/pdf', - 'href': 'http://docs.rackspacecloud.com/' - 'servers/api/v1.1/cs-devguide-20110125.pdf', - }, - { - 'rel': 'describedby', - 'type': 'application/vnd.sun.wadl+xml', - 'href': 'http://docs.rackspacecloud.com/' - 'servers/api/v1.1/application.wadl', - }, - ]) + self.assertEqual(len(entry.links), 3) + self.assertEqual(entry.links[0]['href'], 'http://localhost/v1.1/') + self.assertEqual(entry.links[0]['rel'], 'self') + self.assertEqual(entry.links[1], { + 'rel': 'describedby', + 'type': 'application/pdf', + 'href': 'http://docs.rackspacecloud.com/' + 'servers/api/v1.1/cs-devguide-20110125.pdf'}) + self.assertEqual(entry.links[2], { + 'rel': 'describedby', + 'type': 'application/vnd.sun.wadl+xml', + 'href': 'http://docs.rackspacecloud.com/' + 'servers/api/v1.1/application.wadl', + }) -- cgit From 613bcfc45865c9d7c7577e124b187920970d031e Mon Sep 17 00:00:00 2001 From: Naveed Massjouni Date: Tue, 13 Sep 2011 11:22:45 -0400 Subject: And again. --- nova/tests/api/openstack/test_versions.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/test_versions.py b/nova/tests/api/openstack/test_versions.py index 0077cbe79..f69dbd316 100644 --- a/nova/tests/api/openstack/test_versions.py +++ b/nova/tests/api/openstack/test_versions.py @@ -408,10 +408,9 @@ class VersionsTest(test.TestCase): self.assertEqual(len(entry.content), 1) self.assertEqual(entry.content[0].value, 'Version v1.1 CURRENT (2011-01-21T11:33:21Z)') - self.assertEqual(entry.links, [{ - 'href': 'http://localhost/v1.1/', - 'type': 'application/atom+xml', - 'rel': 'self'}]) + self.assertEqual(len(entry.links), 1) + self.assertEqual(entry.links[0]['href'], 'http://localhost/v1.1/') + self.assertEqual(entry.links[0]['rel'], 'self') def test_multi_choice_image(self): req = webob.Request.blank('/images/1') -- cgit From 98e2fd764b33fa5a3af6ca982a171717a12ee206 Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Tue, 13 Sep 2011 15:33:34 -0500 Subject: Only allow up to 15 chars for a Windows hostname. --- nova/tests/test_xenapi.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'nova/tests') diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index 4a83d139e..47c6a3c95 100644 --- a/nova/tests/test_xenapi.py +++ b/nova/tests/test_xenapi.py @@ -364,7 +364,7 @@ class XenAPIVMTestCase(test.TestCase): def _test_spawn(self, image_ref, kernel_id, ramdisk_id, instance_type_id="3", os_type="linux", - architecture="x86-64", instance_id=1, + hostname="test", architecture="x86-64", instance_id=1, check_injection=False, create_record=True, empty_dns=False): stubs.stubout_loopingcall_start(self.stubs) @@ -377,6 +377,7 @@ class XenAPIVMTestCase(test.TestCase): 'ramdisk_id': ramdisk_id, 'instance_type_id': instance_type_id, 'os_type': os_type, + 'hostname': hostname, 'architecture': architecture} instance = db.instance_create(self.context, values) else: -- cgit