diff --git a/nova/tests/unit/compute/test_flavors.py b/nova/tests/unit/compute/test_flavors.py index 3329ae0bb865..d296aeed9005 100644 --- a/nova/tests/unit/compute/test_flavors.py +++ b/nova/tests/unit/compute/test_flavors.py @@ -16,46 +16,277 @@ """Tests for flavor basic functions""" from nova.compute import flavors +from nova import context +from nova.db import api as db from nova import exception +from nova import objects +from nova.objects import base as obj_base from nova import test -class ExtraSpecTestCase(test.NoDBTestCase): - def _flavor_validate_extra_spec_keys_invalid_input(self, key_name_list): - self.assertRaises(exception.InvalidInput, - flavors.validate_extra_spec_keys, key_name_list) +class TestValidateExtraSpecKeys(test.NoDBTestCase): def test_flavor_validate_extra_spec_keys_invalid_input(self): - lists = [['', ], ['*', ], ['+', ]] - for x in lists: - self._flavor_validate_extra_spec_keys_invalid_input(x) + for key_name_list in [['', ], ['*', ], ['+', ]]: + self.assertRaises( + exception.InvalidInput, + flavors.validate_extra_spec_keys, key_name_list) def test_flavor_validate_extra_spec_keys(self): key_name_list = ['abc', 'ab c', 'a-b-c', 'a_b-c', 'a:bc'] flavors.validate_extra_spec_keys(key_name_list) -class CreateFlavorTestCase(test.NoDBTestCase): - def test_create_flavor_ram_error(self): - args = ("ram_test", "9999999999", "1", "10", "1") - try: - flavors.create(*args) - self.fail("Be sure this will never be executed.") - except exception.InvalidInput as e: - self.assertIn("ram", e.message) +class TestGetFlavorByFlavorID(test.TestCase): + """Test cases for flavor code.""" + def test_will_not_get_instance_by_unknown_flavor_id(self): + # Ensure get by flavor raises error with wrong flavorid. + self.assertRaises(exception.FlavorNotFound, + flavors.get_flavor_by_flavor_id, + 'unknown_flavor') - def test_create_flavor_disk_error(self): - args = ("disk_test", "1024", "1", "9999999999", "1") - try: - flavors.create(*args) - self.fail("Be sure this will never be executed.") - except exception.InvalidInput as e: - self.assertIn("disk", e.message) + def test_will_get_instance_by_flavor_id(self): + default_flavor = objects.Flavor.get_by_name( + context.get_admin_context(), 'm1.small') + flavorid = default_flavor.flavorid + fetched = flavors.get_flavor_by_flavor_id(flavorid) + self.assertIsInstance(fetched, objects.Flavor) + self.assertEqual(default_flavor.flavorid, fetched.flavorid) - def test_create_flavor_ephemeral_error(self): - args = ("ephemeral_test", "1024", "1", "10", "9999999999") - try: - flavors.create(*args) - self.fail("Be sure this will never be executed.") - except exception.InvalidInput as e: - self.assertIn("ephemeral", e.message) + +class TestExtractFlavor(test.TestCase): + + def setUp(self): + super().setUp() + self.context = context.get_admin_context() + + def _dict_to_metadata(self, data): + return [{'key': key, 'value': value} for key, value in data.items()] + + def _test_extract_flavor(self, prefix): + flavor = objects.Flavor.get_by_name(self.context, 'm1.small') + flavor_p = obj_base.obj_to_primitive(flavor) + + metadata = {} + flavors.save_flavor_info(metadata, flavor, prefix) + instance = {'system_metadata': self._dict_to_metadata(metadata)} + _flavor = flavors.extract_flavor(instance, prefix) + _flavor_p = obj_base.obj_to_primitive(_flavor) + + props = flavors.system_metadata_flavor_props.keys() + for key in list(flavor_p.keys()): + if key not in props: + del flavor_p[key] + + self.assertEqual(flavor_p, _flavor_p) + + def test_extract_flavor(self): + self._test_extract_flavor('') + + def test_extract_flavor_no_sysmeta(self): + instance = {} + prefix = '' + result = flavors.extract_flavor(instance, prefix) + + self.assertIsNone(result) + + def test_extract_flavor_prefix(self): + self._test_extract_flavor('foo_') + + +class TestSaveFlavorInfo(test.TestCase): + + def setUp(self): + super().setUp() + self.context = context.get_admin_context() + + def test_save_flavor_info(self): + flavor = objects.Flavor.get_by_name(self.context, 'm1.small') + + example = {} + example_prefix = {} + + for key in flavors.system_metadata_flavor_props.keys(): + example['instance_type_%s' % key] = flavor[key] + example_prefix['fooinstance_type_%s' % key] = flavor[key] + + metadata = {} + flavors.save_flavor_info(metadata, flavor) + self.assertEqual(example, metadata) + + metadata = {} + flavors.save_flavor_info(metadata, flavor, 'foo') + self.assertEqual(example_prefix, metadata) + + def test_flavor_numa_extras_are_saved(self): + flavor = objects.Flavor.get_by_name(self.context, 'm1.small') + flavor['extra_specs'] = { + 'hw:numa_mem.0': '123', + 'hw:numa_cpus.0': '456', + 'hw:numa_mem.1': '789', + 'hw:numa_cpus.1': 'ABC', + 'foo': 'bar', + } + sysmeta = flavors.save_flavor_info({}, flavor) + _flavor = flavors.extract_flavor({'system_metadata': sysmeta}) + expected_extra_specs = { + 'hw:numa_mem.0': '123', + 'hw:numa_cpus.0': '456', + 'hw:numa_mem.1': '789', + 'hw:numa_cpus.1': 'ABC', + } + self.assertEqual(expected_extra_specs, _flavor['extra_specs']) + + +class TestCreateFlavor(test.TestCase): + + def assertInvalidInput(self, *create_args, **create_kwargs): + self.assertRaises( + exception.InvalidInput, flavors.create, + *create_args, **create_kwargs) + + def test_memory_must_be_positive_db_integer(self): + self.assertInvalidInput('flavor1', 'foo', 1, 120) + self.assertInvalidInput('flavor1', -1, 1, 120) + self.assertInvalidInput('flavor1', 0, 1, 120) + self.assertInvalidInput('flavor1', db.MAX_INT + 1, 1, 120) + flavors.create('flavor1', 1, 1, 120) + + def test_vcpus_must_be_positive_db_integer(self): + self.assertInvalidInput('flavor`', 64, 'foo', 120) + self.assertInvalidInput('flavor1', 64, -1, 120) + self.assertInvalidInput('flavor1', 64, 0, 120) + self.assertInvalidInput('flavor1', 64, db.MAX_INT + 1, 120) + flavors.create('flavor1', 64, 1, 120) + + def test_root_gb_must_be_nonnegative_db_integer(self): + self.assertInvalidInput('flavor1', 64, 1, 'foo') + self.assertInvalidInput('flavor1', 64, 1, -1) + self.assertInvalidInput('flavor1', 64, 1, db.MAX_INT + 1) + flavors.create('flavor1', 64, 1, 0) + flavors.create('flavor2', 64, 1, 120) + + def test_ephemeral_gb_must_be_nonnegative_db_integer(self): + self.assertInvalidInput('flavor1', 64, 1, 120, ephemeral_gb='foo') + self.assertInvalidInput('flavor1', 64, 1, 120, ephemeral_gb=-1) + self.assertInvalidInput('flavor1', 64, 1, 120, + ephemeral_gb=db.MAX_INT + 1) + flavors.create('flavor1', 64, 1, 120, ephemeral_gb=0) + flavors.create('flavor2', 64, 1, 120, ephemeral_gb=120) + + def test_swap_must_be_nonnegative_db_integer(self): + self.assertInvalidInput('flavor1', 64, 1, 120, swap='foo') + self.assertInvalidInput('flavor1', 64, 1, 120, swap=-1) + self.assertInvalidInput('flavor1', 64, 1, 120, swap=db.MAX_INT + 1) + flavors.create('flavor1', 64, 1, 120, swap=0) + flavors.create('flavor2', 64, 1, 120, swap=1) + + def test_rxtx_factor_must_be_positive_float(self): + self.assertInvalidInput('flavor1', 64, 1, 120, rxtx_factor='foo') + self.assertInvalidInput('flavor1', 64, 1, 120, rxtx_factor=-1.0) + self.assertInvalidInput('flavor1', 64, 1, 120, rxtx_factor=0.0) + + flavor = flavors.create('flavor1', 64, 1, 120, rxtx_factor=1.0) + self.assertEqual(1.0, flavor.rxtx_factor) + + flavor = flavors.create('flavor2', 64, 1, 120, rxtx_factor=1.1) + self.assertEqual(1.1, flavor.rxtx_factor) + + def test_rxtx_factor_must_be_within_sql_float_range(self): + # We do * 10 since this is an approximation and we need to make sure + # the difference is noticeble. + over_rxtx_factor = db.SQL_SP_FLOAT_MAX * 10 + + self.assertInvalidInput('flavor1', 64, 1, 120, + rxtx_factor=over_rxtx_factor) + + flavor = flavors.create('flavor2', 64, 1, 120, + rxtx_factor=db.SQL_SP_FLOAT_MAX) + self.assertEqual(db.SQL_SP_FLOAT_MAX, flavor.rxtx_factor) + + def test_is_public_must_be_valid_bool_string(self): + self.assertInvalidInput('flavor1', 64, 1, 120, is_public='foo') + + flavors.create('flavor1', 64, 1, 120, is_public='TRUE') + flavors.create('flavor2', 64, 1, 120, is_public='False') + flavors.create('flavor3', 64, 1, 120, is_public='Yes') + flavors.create('flavor4', 64, 1, 120, is_public='No') + flavors.create('flavor5', 64, 1, 120, is_public='Y') + flavors.create('flavor6', 64, 1, 120, is_public='N') + flavors.create('flavor7', 64, 1, 120, is_public='1') + flavors.create('flavor8', 64, 1, 120, is_public='0') + flavors.create('flavor9', 64, 1, 120, is_public='true') + + def test_flavorid_populated(self): + flavor1 = flavors.create('flavor1', 64, 1, 120) + self.assertIsNotNone(flavor1.flavorid) + + flavor2 = flavors.create('flavor2', 64, 1, 120, flavorid='') + self.assertIsNotNone(flavor2.flavorid) + + flavor3 = flavors.create('flavor3', 64, 1, 120, flavorid='foo') + self.assertEqual('foo', flavor3.flavorid) + + def test_default_values(self): + flavor1 = flavors.create('flavor1', 64, 1, 120) + + self.assertIsNotNone(flavor1.flavorid) + self.assertEqual(flavor1.ephemeral_gb, 0) + self.assertEqual(flavor1.swap, 0) + self.assertEqual(flavor1.rxtx_factor, 1.0) + + def test_basic_create(self): + # Ensure instance types can be created. + ctxt = context.get_admin_context() + original_list = objects.FlavorList.get_all(ctxt) + + # Create new type and make sure values stick + flavor = flavors.create('flavor', 64, 1, 120) + self.assertEqual(flavor.name, 'flavor') + self.assertEqual(flavor.memory_mb, 64) + self.assertEqual(flavor.vcpus, 1) + self.assertEqual(flavor.root_gb, 120) + + # Ensure new type shows up in list + new_list = objects.FlavorList.get_all(ctxt) + self.assertNotEqual( + len(original_list), len(new_list), + 'flavor was not created') + + def test_create_then_delete(self): + ctxt = context.get_admin_context() + original_list = objects.FlavorList.get_all(ctxt) + + flavor = flavors.create('flavor', 64, 1, 120) + + # Ensure new type shows up in list + new_list = objects.FlavorList.get_all(ctxt) + self.assertNotEqual( + len(original_list), len(new_list), + 'instance type was not created') + + flavor.destroy() + self.assertRaises( + exception.FlavorNotFound, + objects.Flavor.get_by_name, ctxt, flavor.name) + + # Deleted instance should not be in list anymore + new_list = objects.FlavorList.get_all(ctxt) + self.assertEqual(len(original_list), len(new_list)) + for i, f in enumerate(original_list): + self.assertIsInstance(f, objects.Flavor) + self.assertEqual(f.flavorid, new_list[i].flavorid) + + def test_duplicate_names_fail(self): + # Ensures that name duplicates raise FlavorExists + flavors.create('flavor', 256, 1, 120, 200, 'flavor1') + self.assertRaises( + exception.FlavorExists, + flavors.create, 'flavor', 64, 1, 120) + + def test_duplicate_flavorids_fail(self): + # Ensures that flavorid duplicates raise FlavorExists + flavors.create('flavor1', 64, 1, 120, flavorid='flavorid') + self.assertRaises( + exception.FlavorIdExists, + flavors.create, 'flavor2', 64, 1, 120, flavorid='flavorid') diff --git a/nova/tests/unit/objects/test_flavor.py b/nova/tests/unit/objects/test_flavor.py index 21ec57be2c95..8d89c36b64de 100644 --- a/nova/tests/unit/objects/test_flavor.py +++ b/nova/tests/unit/objects/test_flavor.py @@ -23,7 +23,9 @@ from nova.db.sqlalchemy import api as db_api from nova.db.sqlalchemy import api_models from nova import exception from nova import objects +from nova.objects import fields from nova.objects import flavor as flavor_obj +from nova import test from nova.tests.unit.objects import test_objects @@ -447,3 +449,124 @@ class TestFlavorList(test_objects._LocalTest, _TestFlavorList): class TestFlavorListRemote(test_objects._RemoteTest, _TestFlavorList): pass + + +class TestFlavorExtraSpecs(test.TestCase): + + def setUp(self): + super().setUp() + self.context = nova_context.get_admin_context() + flavor = objects.Flavor( + context=self.context, + name="cg1.4xlarge", + memory_mb=22000, + vcpus=8, + root_gb=1690, + ephemeral_gb=2000, + flavorid=105) + self.specs = { + 'cpu_arch': fields.Architecture.X86_64, + 'cpu_model': 'Nehalem', + 'xpu_arch': 'fermi', + 'xpus': '2', + 'xpu_model': 'Tesla 2050', + } + flavor.extra_specs = self.specs + flavor.create() + self.flavor = flavor + self.flavorid = flavor.flavorid + + def tearDown(self): + # Remove the instance type from the database + self.flavor.destroy() + super().tearDown() + + def test_flavor_extra_specs_get(self): + flavor = objects.Flavor.get_by_flavor_id(self.context, self.flavorid) + self.assertEqual(self.specs, flavor.extra_specs) + + def test_flavor_extra_specs_delete(self): + del self.specs["xpu_model"] + del self.flavor.extra_specs['xpu_model'] + self.flavor.save() + flavor = objects.Flavor.get_by_flavor_id(self.context, self.flavorid) + self.assertEqual(self.specs, flavor.extra_specs) + + def test_flavor_extra_specs_update(self): + self.specs["cpu_model"] = "Sandy Bridge" + self.flavor.extra_specs["cpu_model"] = "Sandy Bridge" + self.flavor.save() + flavor = objects.Flavor.get_by_flavor_id(self.context, self.flavorid) + self.assertEqual(self.specs, flavor.extra_specs) + + def test_flavor_extra_specs_create(self): + net_attrs = { + "net_arch": "ethernet", + "net_mbps": "10000" + } + self.specs.update(net_attrs) + self.flavor.extra_specs.update(net_attrs) + self.flavor.save() + flavor = objects.Flavor.get_by_flavor_id(self.context, self.flavorid) + self.assertEqual(self.specs, flavor.extra_specs) + + def test_flavor_get_with_extra_specs(self): + flavor = objects.Flavor.get_by_id(self.context, 5) + self.assertEqual(flavor.extra_specs, {}) + + def test_flavor_get_by_name_with_extra_specs(self): + flavor = objects.Flavor.get_by_name(self.context, "cg1.4xlarge") + self.assertEqual(flavor.extra_specs, self.specs) + flavor = objects.Flavor.get_by_name(self.context, "m1.small") + self.assertEqual(flavor.extra_specs, {}) + + def test_flavor_get_by_flavor_id_with_extra_specs(self): + flavor = objects.Flavor.get_by_flavor_id(self.context, 105) + self.assertEqual(flavor.extra_specs, self.specs) + flavor = objects.Flavor.get_by_flavor_id(self.context, 2) + self.assertEqual(flavor.extra_specs, {}) + + def test_flavor_get_all(self): + flavors = objects.FlavorList.get_all(self.context) + + name2specs = {flavor.name: flavor.extra_specs + for flavor in flavors} + + self.assertEqual(name2specs['cg1.4xlarge'], self.specs) + self.assertEqual(name2specs['m1.small'], {}) + + +class TestFlavorFiltering(test.TestCase): + """Test cases for the filter option available for FlavorList.get_all.""" + def setUp(self): + super().setUp() + self.context = nova_context.get_admin_context() + + def assertFilterResults(self, filters, expected): + flavors = objects.FlavorList.get_all(self.context, filters=filters) + inst_names = [i.name for i in flavors] + self.assertEqual(inst_names, expected) + + def test_no_filters(self): + filters = None + expected = ['m1.tiny', 'm1.small', 'm1.medium', 'm1.large', + 'm1.xlarge', 'm1.tiny.specs'] + self.assertFilterResults(filters, expected) + + def test_min_memory_mb_filter(self): + # Exclude tiny instance which is 512 MB. + filters = {'min_memory_mb': 513} + expected = ['m1.small', 'm1.medium', 'm1.large', 'm1.xlarge'] + self.assertFilterResults(filters, expected) + + def test_min_root_gb_filter(self): + # Exclude everything but large and xlarge which have >= 80 GB. + filters = {'min_root_gb': 80} + expected = ['m1.large', 'm1.xlarge'] + self.assertFilterResults(filters, expected) + + def test_min_memory_mb_AND_root_gb_filter(self): + # Exclude everything but large and xlarge which have >= 80 GB. + filters = {'min_memory_mb': 16384, 'min_root_gb': 80} + expected = ['m1.xlarge'] + self.assertFilterResults(filters, expected) diff --git a/nova/tests/unit/test_flavor_extra_specs.py b/nova/tests/unit/test_flavor_extra_specs.py deleted file mode 100644 index 1033f1373ca0..000000000000 --- a/nova/tests/unit/test_flavor_extra_specs.py +++ /dev/null @@ -1,104 +0,0 @@ -# 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 instance types extra specs code -""" - -from nova import context -from nova import objects -from nova.objects import fields -from nova import test - - -class InstanceTypeExtraSpecsTestCase(test.TestCase): - - def setUp(self): - super(InstanceTypeExtraSpecsTestCase, self).setUp() - self.context = context.get_admin_context() - flavor = objects.Flavor(context=self.context, - name="cg1.4xlarge", - memory_mb=22000, - vcpus=8, - root_gb=1690, - ephemeral_gb=2000, - flavorid=105) - self.specs = dict(cpu_arch=fields.Architecture.X86_64, - cpu_model="Nehalem", - xpu_arch="fermi", - xpus="2", - xpu_model="Tesla 2050") - flavor.extra_specs = self.specs - flavor.create() - self.flavor = flavor - self.flavorid = flavor.flavorid - - def tearDown(self): - # Remove the instance type from the database - self.flavor.destroy() - super(InstanceTypeExtraSpecsTestCase, self).tearDown() - - def test_flavor_extra_specs_get(self): - flavor = objects.Flavor.get_by_flavor_id(self.context, self.flavorid) - self.assertEqual(self.specs, flavor.extra_specs) - - def test_flavor_extra_specs_delete(self): - del self.specs["xpu_model"] - del self.flavor.extra_specs['xpu_model'] - self.flavor.save() - flavor = objects.Flavor.get_by_flavor_id(self.context, self.flavorid) - self.assertEqual(self.specs, flavor.extra_specs) - - def test_flavor_extra_specs_update(self): - self.specs["cpu_model"] = "Sandy Bridge" - self.flavor.extra_specs["cpu_model"] = "Sandy Bridge" - self.flavor.save() - flavor = objects.Flavor.get_by_flavor_id(self.context, self.flavorid) - self.assertEqual(self.specs, flavor.extra_specs) - - def test_flavor_extra_specs_create(self): - net_attrs = { - "net_arch": "ethernet", - "net_mbps": "10000" - } - self.specs.update(net_attrs) - self.flavor.extra_specs.update(net_attrs) - self.flavor.save() - flavor = objects.Flavor.get_by_flavor_id(self.context, self.flavorid) - self.assertEqual(self.specs, flavor.extra_specs) - - def test_flavor_get_with_extra_specs(self): - flavor = objects.Flavor.get_by_id(self.context, 5) - self.assertEqual(flavor.extra_specs, {}) - - def test_flavor_get_by_name_with_extra_specs(self): - flavor = objects.Flavor.get_by_name(self.context, - "cg1.4xlarge") - self.assertEqual(flavor.extra_specs, self.specs) - flavor = objects.Flavor.get_by_name(self.context, - "m1.small") - self.assertEqual(flavor.extra_specs, {}) - - def test_flavor_get_by_flavor_id_with_extra_specs(self): - flavor = objects.Flavor.get_by_flavor_id(self.context, 105) - self.assertEqual(flavor.extra_specs, self.specs) - flavor = objects.Flavor.get_by_flavor_id(self.context, 2) - self.assertEqual(flavor.extra_specs, {}) - - def test_flavor_get_all(self): - flavors = objects.FlavorList.get_all(self.context) - - name2specs = {flavor.name: flavor.extra_specs - for flavor in flavors} - - self.assertEqual(name2specs['cg1.4xlarge'], self.specs) - self.assertEqual(name2specs['m1.small'], {}) diff --git a/nova/tests/unit/test_flavors.py b/nova/tests/unit/test_flavors.py deleted file mode 100644 index 80fa6d84dc7b..000000000000 --- a/nova/tests/unit/test_flavors.py +++ /dev/null @@ -1,303 +0,0 @@ -# Copyright 2011 Ken Pepple -# 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 flavors code -""" -from nova.compute import flavors -from nova import context -from nova.db import api as db -from nova import exception -from nova import objects -from nova.objects import base as obj_base -from nova import test - - -class FlavorTestCase(test.TestCase): - """Test cases for flavor code.""" - def test_will_not_get_instance_by_unknown_flavor_id(self): - # Ensure get by flavor raises error with wrong flavorid. - self.assertRaises(exception.FlavorNotFound, - flavors.get_flavor_by_flavor_id, - 'unknown_flavor') - - def test_will_get_instance_by_flavor_id(self): - default_flavor = objects.Flavor.get_by_name( - context.get_admin_context(), 'm1.small') - flavorid = default_flavor.flavorid - fetched = flavors.get_flavor_by_flavor_id(flavorid) - self.assertIsInstance(fetched, objects.Flavor) - self.assertEqual(default_flavor.flavorid, fetched.flavorid) - - -class FlavorToolsTest(test.TestCase): - - def setUp(self): - super().setUp() - self.context = context.get_admin_context() - - def _dict_to_metadata(self, data): - return [{'key': key, 'value': value} for key, value in data.items()] - - def _test_extract_flavor(self, prefix): - flavor = objects.Flavor.get_by_name(self.context, 'm1.small') - flavor_p = obj_base.obj_to_primitive(flavor) - - metadata = {} - flavors.save_flavor_info(metadata, flavor, prefix) - instance = {'system_metadata': self._dict_to_metadata(metadata)} - _flavor = flavors.extract_flavor(instance, prefix) - _flavor_p = obj_base.obj_to_primitive(_flavor) - - props = flavors.system_metadata_flavor_props.keys() - for key in list(flavor_p.keys()): - if key not in props: - del flavor_p[key] - - self.assertEqual(flavor_p, _flavor_p) - - def test_extract_flavor(self): - self._test_extract_flavor('') - - def test_extract_flavor_no_sysmeta(self): - instance = {} - prefix = '' - result = flavors.extract_flavor(instance, prefix) - - self.assertIsNone(result) - - def test_extract_flavor_prefix(self): - self._test_extract_flavor('foo_') - - def test_save_flavor_info(self): - flavor = objects.Flavor.get_by_name(self.context, 'm1.small') - - example = {} - example_prefix = {} - - for key in flavors.system_metadata_flavor_props.keys(): - example['instance_type_%s' % key] = flavor[key] - example_prefix['fooinstance_type_%s' % key] = flavor[key] - - metadata = {} - flavors.save_flavor_info(metadata, flavor) - self.assertEqual(example, metadata) - - metadata = {} - flavors.save_flavor_info(metadata, flavor, 'foo') - self.assertEqual(example_prefix, metadata) - - def test_flavor_numa_extras_are_saved(self): - flavor = objects.Flavor.get_by_name(self.context, 'm1.small') - flavor['extra_specs'] = { - 'hw:numa_mem.0': '123', - 'hw:numa_cpus.0': '456', - 'hw:numa_mem.1': '789', - 'hw:numa_cpus.1': 'ABC', - 'foo': 'bar', - } - sysmeta = flavors.save_flavor_info({}, flavor) - _flavor = flavors.extract_flavor({'system_metadata': sysmeta}) - expected_extra_specs = { - 'hw:numa_mem.0': '123', - 'hw:numa_cpus.0': '456', - 'hw:numa_mem.1': '789', - 'hw:numa_cpus.1': 'ABC', - } - self.assertEqual(expected_extra_specs, _flavor['extra_specs']) - - -class FlavorFilteringTest(test.TestCase): - """Test cases for the filter option available for FlavorList.get_all.""" - def setUp(self): - super().setUp() - self.context = context.get_admin_context() - - def assertFilterResults(self, filters, expected): - flavors = objects.FlavorList.get_all(self.context, filters=filters) - inst_names = [i.name for i in flavors] - self.assertEqual(inst_names, expected) - - def test_no_filters(self): - filters = None - expected = ['m1.tiny', 'm1.small', 'm1.medium', 'm1.large', - 'm1.xlarge', 'm1.tiny.specs'] - self.assertFilterResults(filters, expected) - - def test_min_memory_mb_filter(self): - # Exclude tiny instance which is 512 MB. - filters = dict(min_memory_mb=513) - expected = ['m1.small', 'm1.medium', 'm1.large', 'm1.xlarge'] - self.assertFilterResults(filters, expected) - - def test_min_root_gb_filter(self): - # Exclude everything but large and xlarge which have >= 80 GB. - filters = dict(min_root_gb=80) - expected = ['m1.large', 'm1.xlarge'] - self.assertFilterResults(filters, expected) - - def test_min_memory_mb_AND_root_gb_filter(self): - # Exclude everything but large and xlarge which have >= 80 GB. - filters = dict(min_memory_mb=16384, min_root_gb=80) - expected = ['m1.xlarge'] - self.assertFilterResults(filters, expected) - - -class CreateFlavorTest(test.TestCase): - - def assertInvalidInput(self, *create_args, **create_kwargs): - self.assertRaises(exception.InvalidInput, flavors.create, - *create_args, **create_kwargs) - - def test_memory_must_be_positive_db_integer(self): - self.assertInvalidInput('flavor1', 'foo', 1, 120) - self.assertInvalidInput('flavor1', -1, 1, 120) - self.assertInvalidInput('flavor1', 0, 1, 120) - self.assertInvalidInput('flavor1', db.MAX_INT + 1, 1, 120) - flavors.create('flavor1', 1, 1, 120) - - def test_vcpus_must_be_positive_db_integer(self): - self.assertInvalidInput('flavor`', 64, 'foo', 120) - self.assertInvalidInput('flavor1', 64, -1, 120) - self.assertInvalidInput('flavor1', 64, 0, 120) - self.assertInvalidInput('flavor1', 64, db.MAX_INT + 1, 120) - flavors.create('flavor1', 64, 1, 120) - - def test_root_gb_must_be_nonnegative_db_integer(self): - self.assertInvalidInput('flavor1', 64, 1, 'foo') - self.assertInvalidInput('flavor1', 64, 1, -1) - self.assertInvalidInput('flavor1', 64, 1, db.MAX_INT + 1) - flavors.create('flavor1', 64, 1, 0) - flavors.create('flavor2', 64, 1, 120) - - def test_ephemeral_gb_must_be_nonnegative_db_integer(self): - self.assertInvalidInput('flavor1', 64, 1, 120, ephemeral_gb='foo') - self.assertInvalidInput('flavor1', 64, 1, 120, ephemeral_gb=-1) - self.assertInvalidInput('flavor1', 64, 1, 120, - ephemeral_gb=db.MAX_INT + 1) - flavors.create('flavor1', 64, 1, 120, ephemeral_gb=0) - flavors.create('flavor2', 64, 1, 120, ephemeral_gb=120) - - def test_swap_must_be_nonnegative_db_integer(self): - self.assertInvalidInput('flavor1', 64, 1, 120, swap='foo') - self.assertInvalidInput('flavor1', 64, 1, 120, swap=-1) - self.assertInvalidInput('flavor1', 64, 1, 120, - swap=db.MAX_INT + 1) - flavors.create('flavor1', 64, 1, 120, swap=0) - flavors.create('flavor2', 64, 1, 120, swap=1) - - def test_rxtx_factor_must_be_positive_float(self): - self.assertInvalidInput('flavor1', 64, 1, 120, rxtx_factor='foo') - self.assertInvalidInput('flavor1', 64, 1, 120, rxtx_factor=-1.0) - self.assertInvalidInput('flavor1', 64, 1, 120, rxtx_factor=0.0) - - flavor = flavors.create('flavor1', 64, 1, 120, rxtx_factor=1.0) - self.assertEqual(1.0, flavor.rxtx_factor) - - flavor = flavors.create('flavor2', 64, 1, 120, rxtx_factor=1.1) - self.assertEqual(1.1, flavor.rxtx_factor) - - def test_rxtx_factor_must_be_within_sql_float_range(self): - # We do * 10 since this is an approximation and we need to make sure - # the difference is noticeble. - over_rxtx_factor = db.SQL_SP_FLOAT_MAX * 10 - - self.assertInvalidInput('flavor1', 64, 1, 120, - rxtx_factor=over_rxtx_factor) - - flavor = flavors.create('flavor2', 64, 1, 120, - rxtx_factor=db.SQL_SP_FLOAT_MAX) - self.assertEqual(db.SQL_SP_FLOAT_MAX, flavor.rxtx_factor) - - def test_is_public_must_be_valid_bool_string(self): - self.assertInvalidInput('flavor1', 64, 1, 120, is_public='foo') - - flavors.create('flavor1', 64, 1, 120, is_public='TRUE') - flavors.create('flavor2', 64, 1, 120, is_public='False') - flavors.create('flavor3', 64, 1, 120, is_public='Yes') - flavors.create('flavor4', 64, 1, 120, is_public='No') - flavors.create('flavor5', 64, 1, 120, is_public='Y') - flavors.create('flavor6', 64, 1, 120, is_public='N') - flavors.create('flavor7', 64, 1, 120, is_public='1') - flavors.create('flavor8', 64, 1, 120, is_public='0') - flavors.create('flavor9', 64, 1, 120, is_public='true') - - def test_flavorid_populated(self): - flavor1 = flavors.create('flavor1', 64, 1, 120) - self.assertIsNotNone(flavor1.flavorid) - - flavor2 = flavors.create('flavor2', 64, 1, 120, flavorid='') - self.assertIsNotNone(flavor2.flavorid) - - flavor3 = flavors.create('flavor3', 64, 1, 120, flavorid='foo') - self.assertEqual('foo', flavor3.flavorid) - - def test_default_values(self): - flavor1 = flavors.create('flavor1', 64, 1, 120) - - self.assertIsNotNone(flavor1.flavorid) - self.assertEqual(flavor1.ephemeral_gb, 0) - self.assertEqual(flavor1.swap, 0) - self.assertEqual(flavor1.rxtx_factor, 1.0) - - def test_basic_create(self): - # Ensure instance types can be created. - ctxt = context.get_admin_context() - original_list = objects.FlavorList.get_all(ctxt) - - # Create new type and make sure values stick - flavor = flavors.create('flavor', 64, 1, 120) - self.assertEqual(flavor.name, 'flavor') - self.assertEqual(flavor.memory_mb, 64) - self.assertEqual(flavor.vcpus, 1) - self.assertEqual(flavor.root_gb, 120) - - # Ensure new type shows up in list - new_list = objects.FlavorList.get_all(ctxt) - self.assertNotEqual(len(original_list), len(new_list), - 'flavor was not created') - - def test_create_then_delete(self): - ctxt = context.get_admin_context() - original_list = objects.FlavorList.get_all(ctxt) - - flavor = flavors.create('flavor', 64, 1, 120) - - # Ensure new type shows up in list - new_list = objects.FlavorList.get_all(ctxt) - self.assertNotEqual(len(original_list), len(new_list), - 'instance type was not created') - - flavor.destroy() - self.assertRaises(exception.FlavorNotFound, - objects.Flavor.get_by_name, ctxt, flavor.name) - - # Deleted instance should not be in list anymore - new_list = objects.FlavorList.get_all(ctxt) - self.assertEqual(len(original_list), len(new_list)) - for i, f in enumerate(original_list): - self.assertIsInstance(f, objects.Flavor) - self.assertEqual(f.flavorid, new_list[i].flavorid) - - def test_duplicate_names_fail(self): - # Ensures that name duplicates raise FlavorExists - flavors.create('flavor', 256, 1, 120, 200, 'flavor1') - self.assertRaises(exception.FlavorExists, - flavors.create, - 'flavor', 64, 1, 120) - - def test_duplicate_flavorids_fail(self): - # Ensures that flavorid duplicates raise FlavorExists - flavors.create('flavor1', 64, 1, 120, flavorid='flavorid') - self.assertRaises(exception.FlavorIdExists, - flavors.create, - 'flavor2', 64, 1, 120, flavorid='flavorid')