summaryrefslogtreecommitdiffstats
path: root/nova/tests
diff options
context:
space:
mode:
authorvladimir.p <vladimir@zadarastorage.com>2011-08-25 16:14:44 +0000
committerTarmac <>2011-08-25 16:14:44 +0000
commitae07c417b554d0b26d055a7bd8b3217a59c1966f (patch)
treeab696134c806d40ac239e5b2f6f30bfe1a488920 /nova/tests
parentf136cf119778b4d5d09e607487cf011b9f16dedb (diff)
parent3a2cdb0d9dc3e8a4ebf30bb31b37bb6bca84330f (diff)
Added:
- volume metadata - volume types - volume types extra_specs Volume create API receives volume types & metadata. Work in progress on Openstack APIs for volume types & extra_specs.
Diffstat (limited to 'nova/tests')
-rw-r--r--nova/tests/api/openstack/test_extensions.py1
-rw-r--r--nova/tests/api/openstack/test_volume_types.py171
-rw-r--r--nova/tests/api/openstack/test_volume_types_extra_specs.py181
-rw-r--r--nova/tests/integrated/test_volumes.py17
-rw-r--r--nova/tests/test_volume_types.py207
-rw-r--r--nova/tests/test_volume_types_extra_specs.py132
6 files changed, 709 insertions, 0 deletions
diff --git a/nova/tests/api/openstack/test_extensions.py b/nova/tests/api/openstack/test_extensions.py
index 9f923852d..c78588d65 100644
--- a/nova/tests/api/openstack/test_extensions.py
+++ b/nova/tests/api/openstack/test_extensions.py
@@ -97,6 +97,7 @@ class ExtensionControllerTest(test.TestCase):
"SecurityGroups",
"VirtualInterfaces",
"Volumes",
+ "VolumeTypes",
]
self.ext_list.sort()
diff --git a/nova/tests/api/openstack/test_volume_types.py b/nova/tests/api/openstack/test_volume_types.py
new file mode 100644
index 000000000..192e66854
--- /dev/null
+++ b/nova/tests/api/openstack/test_volume_types.py
@@ -0,0 +1,171 @@
+# Copyright 2011 OpenStack LLC.
+# 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 json
+import stubout
+import webob
+
+from nova import exception
+from nova import context
+from nova import test
+from nova import log as logging
+from nova.volume import volume_types
+from nova.tests.api.openstack import fakes
+
+LOG = logging.getLogger('nova.tests.api.openstack.test_volume_types')
+
+last_param = {}
+
+
+def stub_volume_type(id):
+ specs = {
+ "key1": "value1",
+ "key2": "value2",
+ "key3": "value3",
+ "key4": "value4",
+ "key5": "value5"}
+ return dict(id=id, name='vol_type_%s' % str(id), extra_specs=specs)
+
+
+def return_volume_types_get_all_types(context):
+ return dict(vol_type_1=stub_volume_type(1),
+ vol_type_2=stub_volume_type(2),
+ vol_type_3=stub_volume_type(3))
+
+
+def return_empty_volume_types_get_all_types(context):
+ return {}
+
+
+def return_volume_types_get_volume_type(context, id):
+ if id == "777":
+ raise exception.VolumeTypeNotFound(volume_type_id=id)
+ return stub_volume_type(int(id))
+
+
+def return_volume_types_destroy(context, name):
+ if name == "777":
+ raise exception.VolumeTypeNotFoundByName(volume_type_name=name)
+ pass
+
+
+def return_volume_types_create(context, name, specs):
+ pass
+
+
+def return_volume_types_get_by_name(context, name):
+ if name == "777":
+ raise exception.VolumeTypeNotFoundByName(volume_type_name=name)
+ return stub_volume_type(int(name.split("_")[2]))
+
+
+class VolumeTypesApiTest(test.TestCase):
+ def setUp(self):
+ super(VolumeTypesApiTest, self).setUp()
+ fakes.stub_out_key_pair_funcs(self.stubs)
+
+ def tearDown(self):
+ self.stubs.UnsetAll()
+ super(VolumeTypesApiTest, self).tearDown()
+
+ def test_volume_types_index(self):
+ self.stubs.Set(volume_types, 'get_all_types',
+ return_volume_types_get_all_types)
+ req = webob.Request.blank('/v1.1/123/os-volume-types')
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(200, res.status_int)
+ res_dict = json.loads(res.body)
+ self.assertEqual('application/json', res.headers['Content-Type'])
+
+ self.assertEqual(3, len(res_dict))
+ for name in ['vol_type_1', 'vol_type_2', 'vol_type_3']:
+ self.assertEqual(name, res_dict[name]['name'])
+ self.assertEqual('value1', res_dict[name]['extra_specs']['key1'])
+
+ def test_volume_types_index_no_data(self):
+ self.stubs.Set(volume_types, 'get_all_types',
+ return_empty_volume_types_get_all_types)
+ req = webob.Request.blank('/v1.1/123/os-volume-types')
+ res = req.get_response(fakes.wsgi_app())
+ res_dict = json.loads(res.body)
+ self.assertEqual(200, res.status_int)
+ self.assertEqual('application/json', res.headers['Content-Type'])
+ self.assertEqual(0, len(res_dict))
+
+ def test_volume_types_show(self):
+ self.stubs.Set(volume_types, 'get_volume_type',
+ return_volume_types_get_volume_type)
+ req = webob.Request.blank('/v1.1/123/os-volume-types/1')
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(200, res.status_int)
+ res_dict = json.loads(res.body)
+ self.assertEqual('application/json', res.headers['Content-Type'])
+ self.assertEqual(1, len(res_dict))
+ self.assertEqual('vol_type_1', res_dict['volume_type']['name'])
+
+ def test_volume_types_show_not_found(self):
+ self.stubs.Set(volume_types, 'get_volume_type',
+ return_volume_types_get_volume_type)
+ req = webob.Request.blank('/v1.1/123/os-volume-types/777')
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(404, res.status_int)
+
+ def test_volume_types_delete(self):
+ self.stubs.Set(volume_types, 'get_volume_type',
+ return_volume_types_get_volume_type)
+ self.stubs.Set(volume_types, 'destroy',
+ return_volume_types_destroy)
+ req = webob.Request.blank('/v1.1/123/os-volume-types/1')
+ req.method = 'DELETE'
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(200, res.status_int)
+
+ def test_volume_types_delete_not_found(self):
+ self.stubs.Set(volume_types, 'get_volume_type',
+ return_volume_types_get_volume_type)
+ self.stubs.Set(volume_types, 'destroy',
+ return_volume_types_destroy)
+ req = webob.Request.blank('/v1.1/123/os-volume-types/777')
+ req.method = 'DELETE'
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(404, res.status_int)
+
+ def test_create(self):
+ self.stubs.Set(volume_types, 'create',
+ return_volume_types_create)
+ self.stubs.Set(volume_types, 'get_volume_type_by_name',
+ return_volume_types_get_by_name)
+ req = webob.Request.blank('/v1.1/123/os-volume-types')
+ req.method = 'POST'
+ req.body = '{"volume_type": {"name": "vol_type_1", '\
+ '"extra_specs": {"key1": "value1"}}}'
+ req.headers["content-type"] = "application/json"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(200, res.status_int)
+ res_dict = json.loads(res.body)
+ self.assertEqual('application/json', res.headers['Content-Type'])
+ self.assertEqual(1, len(res_dict))
+ self.assertEqual('vol_type_1', res_dict['volume_type']['name'])
+
+ def test_create_empty_body(self):
+ self.stubs.Set(volume_types, 'create',
+ return_volume_types_create)
+ self.stubs.Set(volume_types, 'get_volume_type_by_name',
+ return_volume_types_get_by_name)
+ req = webob.Request.blank('/v1.1/123/os-volume-types')
+ req.method = 'POST'
+ req.headers["content-type"] = "application/json"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(400, res.status_int)
diff --git a/nova/tests/api/openstack/test_volume_types_extra_specs.py b/nova/tests/api/openstack/test_volume_types_extra_specs.py
new file mode 100644
index 000000000..34bdada22
--- /dev/null
+++ b/nova/tests/api/openstack/test_volume_types_extra_specs.py
@@ -0,0 +1,181 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2011 Zadara Storage Inc.
+# Copyright (c) 2011 OpenStack LLC.
+# Copyright 2011 University of Southern California
+# 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 json
+import stubout
+import webob
+import os.path
+
+
+from nova import test
+from nova.api import openstack
+from nova.api.openstack import extensions
+from nova.tests.api.openstack import fakes
+import nova.wsgi
+
+
+def return_create_volume_type_extra_specs(context, volume_type_id,
+ extra_specs):
+ return stub_volume_type_extra_specs()
+
+
+def return_volume_type_extra_specs(context, volume_type_id):
+ return stub_volume_type_extra_specs()
+
+
+def return_empty_volume_type_extra_specs(context, volume_type_id):
+ return {}
+
+
+def delete_volume_type_extra_specs(context, volume_type_id, key):
+ pass
+
+
+def stub_volume_type_extra_specs():
+ specs = {
+ "key1": "value1",
+ "key2": "value2",
+ "key3": "value3",
+ "key4": "value4",
+ "key5": "value5"}
+ return specs
+
+
+class VolumeTypesExtraSpecsTest(test.TestCase):
+
+ def setUp(self):
+ super(VolumeTypesExtraSpecsTest, self).setUp()
+ fakes.stub_out_key_pair_funcs(self.stubs)
+ self.api_path = '/v1.1/123/os-volume-types/1/extra_specs'
+
+ def test_index(self):
+ self.stubs.Set(nova.db.api, 'volume_type_extra_specs_get',
+ return_volume_type_extra_specs)
+ request = webob.Request.blank(self.api_path)
+ res = request.get_response(fakes.wsgi_app())
+ self.assertEqual(200, res.status_int)
+ res_dict = json.loads(res.body)
+ self.assertEqual('application/json', res.headers['Content-Type'])
+ self.assertEqual('value1', res_dict['extra_specs']['key1'])
+
+ def test_index_no_data(self):
+ self.stubs.Set(nova.db.api, 'volume_type_extra_specs_get',
+ return_empty_volume_type_extra_specs)
+ req = webob.Request.blank(self.api_path)
+ res = req.get_response(fakes.wsgi_app())
+ res_dict = json.loads(res.body)
+ self.assertEqual(200, res.status_int)
+ self.assertEqual('application/json', res.headers['Content-Type'])
+ self.assertEqual(0, len(res_dict['extra_specs']))
+
+ def test_show(self):
+ self.stubs.Set(nova.db.api, 'volume_type_extra_specs_get',
+ return_volume_type_extra_specs)
+ req = webob.Request.blank(self.api_path + '/key5')
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(200, res.status_int)
+ res_dict = json.loads(res.body)
+ self.assertEqual('application/json', res.headers['Content-Type'])
+ self.assertEqual('value5', res_dict['key5'])
+
+ def test_show_spec_not_found(self):
+ self.stubs.Set(nova.db.api, 'volume_type_extra_specs_get',
+ return_empty_volume_type_extra_specs)
+ req = webob.Request.blank(self.api_path + '/key6')
+ res = req.get_response(fakes.wsgi_app())
+ res_dict = json.loads(res.body)
+ self.assertEqual(404, res.status_int)
+
+ def test_delete(self):
+ self.stubs.Set(nova.db.api, 'volume_type_extra_specs_delete',
+ delete_volume_type_extra_specs)
+ req = webob.Request.blank(self.api_path + '/key5')
+ req.method = 'DELETE'
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(200, res.status_int)
+
+ def test_create(self):
+ self.stubs.Set(nova.db.api,
+ 'volume_type_extra_specs_update_or_create',
+ return_create_volume_type_extra_specs)
+ req = webob.Request.blank(self.api_path)
+ req.method = 'POST'
+ req.body = '{"extra_specs": {"key1": "value1"}}'
+ req.headers["content-type"] = "application/json"
+ res = req.get_response(fakes.wsgi_app())
+ res_dict = json.loads(res.body)
+ self.assertEqual(200, res.status_int)
+ self.assertEqual('application/json', res.headers['Content-Type'])
+ self.assertEqual('value1', res_dict['extra_specs']['key1'])
+
+ def test_create_empty_body(self):
+ self.stubs.Set(nova.db.api,
+ 'volume_type_extra_specs_update_or_create',
+ return_create_volume_type_extra_specs)
+ req = webob.Request.blank(self.api_path)
+ req.method = 'POST'
+ req.headers["content-type"] = "application/json"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(400, res.status_int)
+
+ def test_update_item(self):
+ self.stubs.Set(nova.db.api,
+ 'volume_type_extra_specs_update_or_create',
+ return_create_volume_type_extra_specs)
+ req = webob.Request.blank(self.api_path + '/key1')
+ req.method = 'PUT'
+ req.body = '{"key1": "value1"}'
+ req.headers["content-type"] = "application/json"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(200, res.status_int)
+ self.assertEqual('application/json', res.headers['Content-Type'])
+ res_dict = json.loads(res.body)
+ self.assertEqual('value1', res_dict['key1'])
+
+ def test_update_item_empty_body(self):
+ self.stubs.Set(nova.db.api,
+ 'volume_type_extra_specs_update_or_create',
+ return_create_volume_type_extra_specs)
+ req = webob.Request.blank(self.api_path + '/key1')
+ req.method = 'PUT'
+ req.headers["content-type"] = "application/json"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(400, res.status_int)
+
+ def test_update_item_too_many_keys(self):
+ self.stubs.Set(nova.db.api,
+ 'volume_type_extra_specs_update_or_create',
+ return_create_volume_type_extra_specs)
+ req = webob.Request.blank(self.api_path + '/key1')
+ req.method = 'PUT'
+ req.body = '{"key1": "value1", "key2": "value2"}'
+ 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):
+ self.stubs.Set(nova.db.api,
+ 'volume_type_extra_specs_update_or_create',
+ return_create_volume_type_extra_specs)
+ req = webob.Request.blank(self.api_path + '/bad')
+ req.method = 'PUT'
+ req.body = '{"key1": "value1"}'
+ req.headers["content-type"] = "application/json"
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(400, res.status_int)
diff --git a/nova/tests/integrated/test_volumes.py b/nova/tests/integrated/test_volumes.py
index d3e936462..d6c5e1ba1 100644
--- a/nova/tests/integrated/test_volumes.py
+++ b/nova/tests/integrated/test_volumes.py
@@ -285,6 +285,23 @@ class VolumesTest(integrated_helpers._IntegratedTestBase):
self.assertEquals(undisco_move['mountpoint'], device)
self.assertEquals(undisco_move['instance_id'], server_id)
+ def test_create_volume_with_metadata(self):
+ """Creates and deletes a volume."""
+
+ # Create volume
+ metadata = {'key1': 'value1',
+ 'key2': 'value2'}
+ created_volume = self.api.post_volume(
+ {'volume': {'size': 1,
+ 'metadata': metadata}})
+ LOG.debug("created_volume: %s" % created_volume)
+ self.assertTrue(created_volume['id'])
+ created_volume_id = created_volume['id']
+
+ # Check it's there and metadata present
+ found_volume = self.api.get_volume(created_volume_id)
+ self.assertEqual(created_volume_id, found_volume['id'])
+ self.assertEqual(metadata, found_volume['metadata'])
if __name__ == "__main__":
unittest.main()
diff --git a/nova/tests/test_volume_types.py b/nova/tests/test_volume_types.py
new file mode 100644
index 000000000..1e190805c
--- /dev/null
+++ b/nova/tests/test_volume_types.py
@@ -0,0 +1,207 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2011 Zadara Storage Inc.
+# Copyright (c) 2011 OpenStack LLC.
+# 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.
+"""
+Unit Tests for volume types code
+"""
+import time
+
+from nova import context
+from nova import db
+from nova import exception
+from nova import flags
+from nova import log as logging
+from nova import test
+from nova import utils
+from nova.volume import volume_types
+from nova.db.sqlalchemy.session import get_session
+from nova.db.sqlalchemy import models
+
+FLAGS = flags.FLAGS
+LOG = logging.getLogger('nova.tests.test_volume_types')
+
+
+class VolumeTypeTestCase(test.TestCase):
+ """Test cases for volume type code"""
+ def setUp(self):
+ super(VolumeTypeTestCase, self).setUp()
+
+ self.ctxt = context.get_admin_context()
+ self.vol_type1_name = str(int(time.time()))
+ self.vol_type1_specs = dict(
+ type="physical drive",
+ drive_type="SAS",
+ size="300",
+ rpm="7200",
+ visible="True")
+ self.vol_type1 = dict(name=self.vol_type1_name,
+ extra_specs=self.vol_type1_specs)
+
+ def test_volume_type_create_then_destroy(self):
+ """Ensure volume types can be created and deleted"""
+ prev_all_vtypes = volume_types.get_all_types(self.ctxt)
+
+ volume_types.create(self.ctxt,
+ self.vol_type1_name,
+ self.vol_type1_specs)
+ new = volume_types.get_volume_type_by_name(self.ctxt,
+ self.vol_type1_name)
+
+ LOG.info(_("Given data: %s"), self.vol_type1_specs)
+ LOG.info(_("Result data: %s"), new)
+
+ for k, v in self.vol_type1_specs.iteritems():
+ self.assertEqual(v, new['extra_specs'][k],
+ 'one of fields doesnt match')
+
+ new_all_vtypes = volume_types.get_all_types(self.ctxt)
+ self.assertEqual(len(prev_all_vtypes) + 1,
+ len(new_all_vtypes),
+ 'drive type was not created')
+
+ volume_types.destroy(self.ctxt, self.vol_type1_name)
+ new_all_vtypes = volume_types.get_all_types(self.ctxt)
+ self.assertEqual(prev_all_vtypes,
+ new_all_vtypes,
+ 'drive type was not deleted')
+
+ def test_volume_type_create_then_purge(self):
+ """Ensure volume types can be created and deleted"""
+ prev_all_vtypes = volume_types.get_all_types(self.ctxt, inactive=1)
+
+ volume_types.create(self.ctxt,
+ self.vol_type1_name,
+ self.vol_type1_specs)
+ new = volume_types.get_volume_type_by_name(self.ctxt,
+ self.vol_type1_name)
+
+ for k, v in self.vol_type1_specs.iteritems():
+ self.assertEqual(v, new['extra_specs'][k],
+ 'one of fields doesnt match')
+
+ new_all_vtypes = volume_types.get_all_types(self.ctxt, inactive=1)
+ self.assertEqual(len(prev_all_vtypes) + 1,
+ len(new_all_vtypes),
+ 'drive type was not created')
+
+ volume_types.destroy(self.ctxt, self.vol_type1_name)
+ new_all_vtypes2 = volume_types.get_all_types(self.ctxt, inactive=1)
+ self.assertEqual(len(new_all_vtypes),
+ len(new_all_vtypes2),
+ 'drive type was incorrectly deleted')
+
+ volume_types.purge(self.ctxt, self.vol_type1_name)
+ new_all_vtypes2 = volume_types.get_all_types(self.ctxt, inactive=1)
+ self.assertEqual(len(new_all_vtypes) - 1,
+ len(new_all_vtypes2),
+ 'drive type was not purged')
+
+ def test_get_all_volume_types(self):
+ """Ensures that all volume types can be retrieved"""
+ session = get_session()
+ total_volume_types = session.query(models.VolumeTypes).\
+ count()
+ vol_types = volume_types.get_all_types(self.ctxt)
+ self.assertEqual(total_volume_types, len(vol_types))
+
+ def test_non_existant_inst_type_shouldnt_delete(self):
+ """Ensures that volume type creation fails with invalid args"""
+ self.assertRaises(exception.ApiError,
+ volume_types.destroy, self.ctxt, "sfsfsdfdfs")
+
+ def test_repeated_vol_types_should_raise_api_error(self):
+ """Ensures that volume duplicates raises ApiError"""
+ new_name = self.vol_type1_name + "dup"
+ volume_types.create(self.ctxt, new_name)
+ volume_types.destroy(self.ctxt, new_name)
+ self.assertRaises(
+ exception.ApiError,
+ volume_types.create, self.ctxt, new_name)
+
+ def test_invalid_volume_types_params(self):
+ """Ensures that volume type creation fails with invalid args"""
+ self.assertRaises(exception.InvalidVolumeType,
+ volume_types.destroy, self.ctxt, None)
+ self.assertRaises(exception.InvalidVolumeType,
+ volume_types.purge, self.ctxt, None)
+ self.assertRaises(exception.InvalidVolumeType,
+ volume_types.get_volume_type, self.ctxt, None)
+ self.assertRaises(exception.InvalidVolumeType,
+ volume_types.get_volume_type_by_name,
+ self.ctxt, None)
+
+ def test_volume_type_get_by_id_and_name(self):
+ """Ensure volume types get returns same entry"""
+ volume_types.create(self.ctxt,
+ self.vol_type1_name,
+ self.vol_type1_specs)
+ new = volume_types.get_volume_type_by_name(self.ctxt,
+ self.vol_type1_name)
+
+ new2 = volume_types.get_volume_type(self.ctxt, new['id'])
+ self.assertEqual(new, new2)
+
+ def test_volume_type_search_by_extra_spec(self):
+ """Ensure volume types get by extra spec returns correct type"""
+ volume_types.create(self.ctxt, "type1", {"key1": "val1",
+ "key2": "val2"})
+ volume_types.create(self.ctxt, "type2", {"key2": "val2",
+ "key3": "val3"})
+ volume_types.create(self.ctxt, "type3", {"key3": "another_value",
+ "key4": "val4"})
+
+ vol_types = volume_types.get_all_types(self.ctxt,
+ search_opts={'extra_specs': {"key1": "val1"}})
+ LOG.info("vol_types: %s" % vol_types)
+ self.assertEqual(len(vol_types), 1)
+ self.assertTrue("type1" in vol_types.keys())
+ self.assertEqual(vol_types['type1']['extra_specs'],
+ {"key1": "val1", "key2": "val2"})
+
+ vol_types = volume_types.get_all_types(self.ctxt,
+ search_opts={'extra_specs': {"key2": "val2"}})
+ LOG.info("vol_types: %s" % vol_types)
+ self.assertEqual(len(vol_types), 2)
+ self.assertTrue("type1" in vol_types.keys())
+ self.assertTrue("type2" in vol_types.keys())
+
+ vol_types = volume_types.get_all_types(self.ctxt,
+ search_opts={'extra_specs': {"key3": "val3"}})
+ LOG.info("vol_types: %s" % vol_types)
+ self.assertEqual(len(vol_types), 1)
+ self.assertTrue("type2" in vol_types.keys())
+
+ def test_volume_type_search_by_extra_spec_multiple(self):
+ """Ensure volume types get by extra spec returns correct type"""
+ volume_types.create(self.ctxt, "type1", {"key1": "val1",
+ "key2": "val2",
+ "key3": "val3"})
+ volume_types.create(self.ctxt, "type2", {"key2": "val2",
+ "key3": "val3"})
+ volume_types.create(self.ctxt, "type3", {"key1": "val1",
+ "key3": "val3",
+ "key4": "val4"})
+
+ vol_types = volume_types.get_all_types(self.ctxt,
+ search_opts={'extra_specs': {"key1": "val1",
+ "key3": "val3"}})
+ LOG.info("vol_types: %s" % vol_types)
+ self.assertEqual(len(vol_types), 2)
+ self.assertTrue("type1" in vol_types.keys())
+ self.assertTrue("type3" in vol_types.keys())
+ self.assertEqual(vol_types['type1']['extra_specs'],
+ {"key1": "val1", "key2": "val2", "key3": "val3"})
+ self.assertEqual(vol_types['type3']['extra_specs'],
+ {"key1": "val1", "key3": "val3", "key4": "val4"})
diff --git a/nova/tests/test_volume_types_extra_specs.py b/nova/tests/test_volume_types_extra_specs.py
new file mode 100644
index 000000000..017b187a1
--- /dev/null
+++ b/nova/tests/test_volume_types_extra_specs.py
@@ -0,0 +1,132 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2011 Zadara Storage Inc.
+# Copyright (c) 2011 OpenStack LLC.
+# Copyright 2011 University of Southern California
+# 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.
+"""
+Unit Tests for volume types extra specs code
+"""
+
+from nova import context
+from nova import db
+from nova import test
+from nova.db.sqlalchemy.session import get_session
+from nova.db.sqlalchemy import models
+
+
+class VolumeTypeExtraSpecsTestCase(test.TestCase):
+
+ def setUp(self):
+ super(VolumeTypeExtraSpecsTestCase, self).setUp()
+ self.context = context.get_admin_context()
+ self.vol_type1 = dict(name="TEST: Regular volume test")
+ self.vol_type1_specs = dict(vol_extra1="value1",
+ vol_extra2="value2",
+ vol_extra3=3)
+ self.vol_type1['extra_specs'] = self.vol_type1_specs
+ ref = db.api.volume_type_create(self.context, self.vol_type1)
+ self.volume_type1_id = ref.id
+ for k, v in self.vol_type1_specs.iteritems():
+ self.vol_type1_specs[k] = str(v)
+
+ self.vol_type2_noextra = dict(name="TEST: Volume type without extra")
+ ref = db.api.volume_type_create(self.context, self.vol_type2_noextra)
+ self.vol_type2_id = ref.id
+
+ def tearDown(self):
+ # Remove the instance type from the database
+ db.api.volume_type_purge(context.get_admin_context(),
+ self.vol_type1['name'])
+ db.api.volume_type_purge(context.get_admin_context(),
+ self.vol_type2_noextra['name'])
+ super(VolumeTypeExtraSpecsTestCase, self).tearDown()
+
+ def test_volume_type_specs_get(self):
+ expected_specs = self.vol_type1_specs.copy()
+ actual_specs = db.api.volume_type_extra_specs_get(
+ context.get_admin_context(),
+ self.volume_type1_id)
+ self.assertEquals(expected_specs, actual_specs)
+
+ def test_volume_type_extra_specs_delete(self):
+ expected_specs = self.vol_type1_specs.copy()
+ del expected_specs['vol_extra2']
+ db.api.volume_type_extra_specs_delete(context.get_admin_context(),
+ self.volume_type1_id,
+ 'vol_extra2')
+ actual_specs = db.api.volume_type_extra_specs_get(
+ context.get_admin_context(),
+ self.volume_type1_id)
+ self.assertEquals(expected_specs, actual_specs)
+
+ def test_volume_type_extra_specs_update(self):
+ expected_specs = self.vol_type1_specs.copy()
+ expected_specs['vol_extra3'] = "4"
+ db.api.volume_type_extra_specs_update_or_create(
+ context.get_admin_context(),
+ self.volume_type1_id,
+ dict(vol_extra3=4))
+ actual_specs = db.api.volume_type_extra_specs_get(
+ context.get_admin_context(),
+ self.volume_type1_id)
+ self.assertEquals(expected_specs, actual_specs)
+
+ def test_volume_type_extra_specs_create(self):
+ expected_specs = self.vol_type1_specs.copy()
+ expected_specs['vol_extra4'] = 'value4'
+ expected_specs['vol_extra5'] = 'value5'
+ db.api.volume_type_extra_specs_update_or_create(
+ context.get_admin_context(),
+ self.volume_type1_id,
+ dict(vol_extra4="value4",
+ vol_extra5="value5"))
+ actual_specs = db.api.volume_type_extra_specs_get(
+ context.get_admin_context(),
+ self.volume_type1_id)
+ self.assertEquals(expected_specs, actual_specs)
+
+ def test_volume_type_get_with_extra_specs(self):
+ volume_type = db.api.volume_type_get(
+ context.get_admin_context(),
+ self.volume_type1_id)
+ self.assertEquals(volume_type['extra_specs'],
+ self.vol_type1_specs)
+
+ volume_type = db.api.volume_type_get(
+ context.get_admin_context(),
+ self.vol_type2_id)
+ self.assertEquals(volume_type['extra_specs'], {})
+
+ def test_volume_type_get_by_name_with_extra_specs(self):
+ volume_type = db.api.volume_type_get_by_name(
+ context.get_admin_context(),
+ self.vol_type1['name'])
+ self.assertEquals(volume_type['extra_specs'],
+ self.vol_type1_specs)
+
+ volume_type = db.api.volume_type_get_by_name(
+ context.get_admin_context(),
+ self.vol_type2_noextra['name'])
+ self.assertEquals(volume_type['extra_specs'], {})
+
+ def test_volume_type_get_all(self):
+ expected_specs = self.vol_type1_specs.copy()
+
+ types = db.api.volume_type_get_all(context.get_admin_context())
+
+ self.assertEquals(
+ types[self.vol_type1['name']]['extra_specs'], expected_specs)
+
+ self.assertEquals(
+ types[self.vol_type2_noextra['name']]['extra_specs'], {})