From 026269dcc157f710ae2a2f9f335c7446dee80eea Mon Sep 17 00:00:00 2001 From: Martin Kopec Date: Tue, 23 Jan 2018 12:41:23 +0000 Subject: [PATCH] Decouple TempestConf class * config_tempest.py was renamed to main.py - entrypoint for console-script (discover-tempest-config) was changed too * TempestConf class was decoupled from main.py and moved to tempest_conf.py file. Imports of related tests were edited and the order of imports in each file was changed so that other dependencies are first followed by a blank space and then local dependencies are listed. * tests related to TempestConf class were moved to test_tempest_conf.py file Change-Id: Idb235b969ba3c1e320aa3efa7fe77b5c59f4ffc6 --- config_tempest/{config_tempest.py => main.py} | 88 +----------- config_tempest/tempest_conf.py | 127 ++++++++++++++++++ config_tempest/tests/base.py | 10 +- config_tempest/tests/test_config_tempest.py | 122 ++--------------- .../tests/test_config_tempest_image.py | 29 ++-- .../tests/test_config_tempest_network.py | 7 +- .../tests/test_config_tempest_user.py | 40 +++--- config_tempest/tests/test_tempest_conf.py | 112 +++++++++++++++ setup.cfg | 2 +- 9 files changed, 298 insertions(+), 239 deletions(-) rename config_tempest/{config_tempest.py => main.py} (92%) create mode 100644 config_tempest/tempest_conf.py create mode 100644 config_tempest/tests/test_tempest_conf.py diff --git a/config_tempest/config_tempest.py b/config_tempest/main.py similarity index 92% rename from config_tempest/config_tempest.py rename to config_tempest/main.py index 39eedd9c..c3b31eaa 100755 --- a/config_tempest/config_tempest.py +++ b/config_tempest/main.py @@ -43,7 +43,6 @@ import logging import os import shutil import sys -import tempest.config import urllib2 import os_client_config @@ -66,6 +65,7 @@ from tempest.lib.services.identity.v3 import users_client as users_v3_client from tempest.lib.services.image.v2 import images_client from tempest.lib.services.network import networks_client from tempest.lib.services.volume.v2 import services_client +import tempest_conf LOG = logging.getLogger(__name__) @@ -595,88 +595,6 @@ class ClientManager(object): conf.set('identity', 'admin_tenant_id', tenant_id) -class TempestConf(ConfigParser.SafeConfigParser): - # causes the config parser to preserve case of the options - optionxform = str - - # set of pairs `(section, key)` which have a higher priority (are - # user-defined) and will usually not be overwritten by `set()` - priority_sectionkeys = set() - - CONF = tempest.config.TempestConfigPrivate(parse_conf=False) - - def get_bool_value(self, value): - strval = str(value).lower() - if strval == 'true': - return True - elif strval == 'false': - return False - else: - raise ValueError("'%s' is not a boolean" % value) - - def get_defaulted(self, section, key): - if self.has_option(section, key): - return self.get(section, key) - else: - return self.CONF.get(section).get(key) - - def set(self, section, key, value, priority=False): - """Set value in configuration, similar to `SafeConfigParser.set` - - Creates non-existent sections. Keeps track of options which were - specified by the user and should not be normally overwritten. - - :param priority: if True, always over-write the value. If False, don't - over-write an existing value if it was written before with a - priority (i.e. if it was specified by the user) - :returns: True if the value was written, False if not (because of - priority) - """ - if not self.has_section(section) and section.lower() != "default": - self.add_section(section) - if not priority and (section, key) in self.priority_sectionkeys: - LOG.debug("Option '[%s] %s = %s' was defined by user, NOT" - " overwriting into value '%s'", section, key, - self.get(section, key), value) - return False - if priority: - self.priority_sectionkeys.add((section, key)) - LOG.debug("Setting [%s] %s = %s", section, key, value) - ConfigParser.SafeConfigParser.set(self, section, key, value) - return True - - def remove_values(self, args): - """Remove values from configuration file specified in arguments. - - :args - arguments object - """ - for key_path in args.remove: - section, key = key_path.split('.') - try: - conf_values = self.get(section, key).split(',') - remove = args.remove[key_path] - if len(remove) == 0: - # delete all values in section.key - self.remove_option(section, key) - elif len(conf_values) == 1: - # make sure only the value specified by user - # will be deleted if in the key is other value - # than expected, ignore it - if conf_values[0] in args.remove[key_path]: - self.remove_option(section, key) - else: - # exclude all unwanted values from the list - # and preserve the original order of items - conf_values = [v for v in conf_values if v not in remove] - self.set(section, key, ",".join(conf_values)) - except ConfigParser.NoOptionError: - # only inform a user, option specified by him doesn't exist - LOG.error(sys.exc_info()[1]) - except ConfigParser.NoSectionError: - # only inform a user, section specified by him doesn't exist - LOG.error(sys.exc_info()[1]) - - def create_tempest_users(tenants_client, roles_client, users_client, conf, services): """Create users necessary for Tempest if they don't exist already.""" @@ -1114,7 +1032,7 @@ def main(): args = parse_arguments() set_logging(args.debug, args.verbose) - conf = TempestConf() + conf = tempest_conf.TempestConf() cloud_creds = args.config.get('auth') set_options(conf, args.deployer_input, args.non_admin, args.overrides, args.test_accounts, cloud_creds) @@ -1164,7 +1082,7 @@ def main(): # remove all unwanted values if were specified if args.remove != {}: LOG.info("Removing configuration: %s", str(args.remove)) - conf.remove_values(args) + conf.remove_values(args.remove) LOG.info("Creating configuration file %s", os.path.abspath(args.out)) with open(args.out, 'w') as f: conf.write(f) diff --git a/config_tempest/tempest_conf.py b/config_tempest/tempest_conf.py new file mode 100644 index 00000000..900240b6 --- /dev/null +++ b/config_tempest/tempest_conf.py @@ -0,0 +1,127 @@ +# Copyright 2018 Red Hat, Inc. +# 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 ConfigParser +import logging +import sys + +import tempest.config + +LOG = logging.getLogger(__name__) + + +class TempestConf(ConfigParser.SafeConfigParser): + # causes the config parser to preserve case of the options + optionxform = str + + # set of pairs `(section, key)` which have a higher priority (are + # user-defined) and will usually not be overwritten by `set()` + priority_sectionkeys = set() + + CONF = tempest.config.TempestConfigPrivate(parse_conf=False) + + def get_bool_value(self, value): + """Returns boolean value of the string value given. + + :param value: True/False + :type value: String + :returns: Boolean value of the string value given + :rtype: Boolean + """ + strval = str(value).lower() + if strval == 'true': + return True + elif strval == 'false': + return False + else: + raise ValueError("'%s' is not a boolean" % value) + + def get_defaulted(self, section, key): + """Returns default value for the section.key pair. + + :param section: a section in a tempest.conf file + :type section: String + :param key: a key in a section in a tempest.conf file + :type key: String + :returns: default value for the section.key pair + :rtype: String + """ + if self.has_option(section, key): + return self.get(section, key) + else: + return self.CONF.get(section).get(key) + + def set(self, section, key, value, priority=False): + """Set value in configuration, similar to `SafeConfigParser.set` + + Creates non-existent sections. Keeps track of options which were + specified by the user and should not be normally overwritten. + + :param section: a section in a tempest.conf file + :type section: String + :param key: a key in a section in a tempest.conf file + :type key: String + :param priority: if True, always over-write the value. If False, don't + over-write an existing value if it was written before with a + priority (i.e. if it was specified by the user) + :type priority: Boolean + :returns: True if the value was written, False if not (because of + priority) + :rtype: Boolean + """ + if not self.has_section(section) and section.lower() != "default": + self.add_section(section) + if not priority and (section, key) in self.priority_sectionkeys: + LOG.debug("Option '[%s] %s = %s' was defined by user, NOT" + " overwriting into value '%s'", section, key, + self.get(section, key), value) + return False + if priority: + self.priority_sectionkeys.add((section, key)) + LOG.debug("Setting [%s] %s = %s", section, key, value) + ConfigParser.SafeConfigParser.set(self, section, key, value) + return True + + def remove_values(self, to_remove): + """Remove values from configuration file specified in arguments. + + :param to_remove: {'section.key': [values_to_be_removed], ...} + :type to_remove: dict + """ + for key_path in to_remove: + section, key = key_path.split('.') + try: + conf_values = self.get(section, key).split(',') + remove = to_remove[key_path] + if len(remove) == 0: + # delete all values in section.key + self.remove_option(section, key) + elif len(conf_values) == 1: + # make sure only the value specified by user + # will be deleted if in the key is other value + # than expected, ignore it + if conf_values[0] in to_remove[key_path]: + self.remove_option(section, key) + else: + # exclude all unwanted values from the list + # and preserve the original order of items + conf_values = [v for v in conf_values if v not in remove] + self.set(section, key, ",".join(conf_values)) + except ConfigParser.NoOptionError: + # only inform a user, option specified by him doesn't exist + LOG.error(sys.exc_info()[1]) + except ConfigParser.NoSectionError: + # only inform a user, section specified by him doesn't exist + LOG.error(sys.exc_info()[1]) diff --git a/config_tempest/tests/base.py b/config_tempest/tests/base.py index b1397fea..12d43da9 100644 --- a/config_tempest/tests/base.py +++ b/config_tempest/tests/base.py @@ -15,13 +15,15 @@ # License for the specific language governing permissions and limitations # under the License. -from config_tempest import api_discovery as api -from config_tempest import config_tempest as tool from fixtures import MonkeyPatch import json import mock from oslotest import base +from config_tempest import api_discovery as api +from config_tempest import main as tool +from config_tempest import tempest_conf + class BaseConfigTempestTest(base.BaseTestCase): @@ -29,7 +31,7 @@ class BaseConfigTempestTest(base.BaseTestCase): def _get_conf(self, V2, V3): """Creates fake conf for testing purposes""" - conf = tool.TempestConf() + conf = tempest_conf.TempestConf() uri = "http://172.16.52.151:5000/" conf.set("identity", "username", "demo") conf.set("identity", "password", "secret") @@ -46,7 +48,7 @@ class BaseConfigTempestTest(base.BaseTestCase): def _get_alt_conf(self, V2, V3): """Contains newer params in place of the deprecated params""" - conf = tool.TempestConf() + conf = tempest_conf.TempestConf() uri = "http://172.16.52.151:5000/" conf.set("identity", "username", "demo") conf.set("identity", "password", "secret") diff --git a/config_tempest/tests/test_config_tempest.py b/config_tempest/tests/test_config_tempest.py index c1635ebe..6f1c364a 100644 --- a/config_tempest/tests/test_config_tempest.py +++ b/config_tempest/tests/test_config_tempest.py @@ -15,13 +15,14 @@ # License for the specific language governing permissions and limitations # under the License. -from argparse import Namespace -from config_tempest import config_tempest as tool -from config_tempest.tests.base import BaseConfigTempestTest from fixtures import MonkeyPatch import logging import mock +from config_tempest import main as tool +from config_tempest import tempest_conf +from config_tempest.tests.base import BaseConfigTempestTest + # disable logging when running unit tests logging.disable(logging.CRITICAL) @@ -35,7 +36,7 @@ class TestClientManager(BaseConfigTempestTest): def test_get_credentials_v2(self): mock_function = mock.Mock() - function2mock = 'config_tempest.config_tempest.auth.get_credentials' + function2mock = 'config_tempest.main.auth.get_credentials' self.useFixture(MonkeyPatch(function2mock, mock_function)) self.client.get_credentials(self.conf, "name", "Tname", "pass") mock_function.assert_called_with( @@ -46,7 +47,7 @@ class TestClientManager(BaseConfigTempestTest): def test_get_credentials_v3(self): mock_function = mock.Mock() - function2mock = 'config_tempest.config_tempest.auth.get_credentials' + function2mock = 'config_tempest.main.auth.get_credentials' self.useFixture(MonkeyPatch(function2mock, mock_function)) self.client.get_credentials(self.conf, "name", "project_name", "pass", identity_version='v3') @@ -63,7 +64,7 @@ class TestClientManager(BaseConfigTempestTest): # check if method returns correct method - KeystoneV2AuthProvider mock_function = mock.Mock() # mock V2Provider, if other provider is called, it fails - func2mock = 'config_tempest.config_tempest.auth.KeystoneV2AuthProvider' + func2mock = 'config_tempest.main.auth.KeystoneV2AuthProvider' self.useFixture(MonkeyPatch(func2mock, mock_function)) resp = self.client.get_auth_provider(self.conf, "") self.assertEqual(resp, mock_function()) @@ -76,11 +77,11 @@ class TestClientManager(BaseConfigTempestTest): # check if method returns KeystoneV3AuthProvider # make isinstance return True mockIsInstance = mock.Mock(return_value=True) - self.useFixture(MonkeyPatch('config_tempest.config_tempest.isinstance', + self.useFixture(MonkeyPatch('config_tempest.main.isinstance', mockIsInstance)) mock_function = mock.Mock() # mock V3Provider, if other provider is called, it fails - func2mock = 'config_tempest.config_tempest.auth.KeystoneV3AuthProvider' + func2mock = 'config_tempest.main.auth.KeystoneV3AuthProvider' self.useFixture(MonkeyPatch(func2mock, mock_function)) resp = self.client.get_auth_provider(self.conf, "") self.assertEqual(resp, mock_function()) @@ -100,7 +101,7 @@ class TestClientManager(BaseConfigTempestTest): def test_init_manager_as_admin(self): mock_function = mock.Mock(return_value={"id": "my_fake_id"}) - func2mock = ('config_tempest.config_tempest.ProjectsClient.' + func2mock = ('config_tempest.main.ProjectsClient.' 'get_project_by_name') self.useFixture(MonkeyPatch(func2mock, mock_function)) self._get_clients(self.conf, admin=True) @@ -118,7 +119,7 @@ class TestClientManager(BaseConfigTempestTest): self.conf = self._get_alt_conf("v2.0", "v3") self.client = self._get_clients(self.conf) mock_function = mock.Mock(return_value={"id": "my_fake_id"}) - func2mock = ('config_tempest.config_tempest.ProjectsClient' + func2mock = ('config_tempest.main.ProjectsClient' '.get_project_by_name') self.useFixture(MonkeyPatch(func2mock, mock_function)) self._get_clients(self.conf, admin=True) @@ -161,7 +162,7 @@ class TestOsClientConfigSupport(BaseConfigTempestTest): func2mock = 'os_client_config.cloud_config.CloudConfig.config.get' self.useFixture(MonkeyPatch(func2mock, mock_function)) mock_function = mock.Mock(return_value={"id": "my_fake_id"}) - func2mock = ('config_tempest.config_tempest.ProjectsClient.' + func2mock = ('config_tempest.main.ProjectsClient.' 'get_project_by_name') self.useFixture(MonkeyPatch(func2mock, mock_function)) @@ -173,7 +174,7 @@ class TestOsClientConfigSupport(BaseConfigTempestTest): 'auth_url': 'http://auth.url.com/' } # create an empty conf - conf = tool.TempestConf() + conf = tempest_conf.TempestConf() conf.set('identity', 'uri', cloud_args['auth_url'], priority=True) # call the function and check if data were obtained properly tool.set_cloud_config_values(non_admin, cloud_args, conf) @@ -229,101 +230,6 @@ class TestOsClientConfigSupport(BaseConfigTempestTest): self.conf.get('identity', 'admin_tenant_name')) -class TestTempestConf(BaseConfigTempestTest): - def setUp(self): - super(TestTempestConf, self).setUp() - self.conf = tool.TempestConf() - - def test_set_value(self): - resp = self.conf.set("section", "key", "value") - self.assertTrue(resp) - self.assertEqual(self.conf.get("section", "key"), "value") - self.assertEqual(self.conf.get_defaulted("section", "key"), "value") - - def test_set_value_overwrite(self): - # set value wihout priority (default: priority=False) - resp = self.conf.set("section", "key", "value") - # value should be overwritten, because it wasn't set with priority - resp = self.conf.set("section", "key", "value") - self.assertTrue(resp) - - def test_set_value_overwrite_priority(self): - resp = self.conf.set("sectionPriority", "key", "value", priority=True) - resp = self.conf.set("sectionPriority", "key", "value") - self.assertFalse(resp) - - def test_set_value_overwrite_by_priority(self): - resp = self.conf.set("section", "key", "value") - resp = self.conf.set("section", "key", "value", priority=True) - self.assertTrue(resp) - - def test_set_value_overwrite_priority_by_priority(self): - resp = self.conf.set("sectionPriority", "key", "value", priority=True) - resp = self.conf.set("sectionPriority", "key", "value", priority=True) - self.assertTrue(resp) - - def test_get_bool_value(self): - self.assertTrue(self.conf.get_bool_value("True")) - self.assertFalse(self.conf.get_bool_value("False")) - self.assertRaises(ValueError, self.conf.get_bool_value, "no") - - def test_remove_values(self): - api_exts = "router_availability_zone,rbac-policies,pagination,sorting," - api_exts += "standard-attr-description,router,binding,metering," - api_exts += "allowed-address-pairs,project-id,dvr,l3-flavors,tag-ext" - remove_exts = ["router", "project-id", "dvr"] - args = Namespace( - remove={ - "identity.username": ["demo"], - "identity.tenant_name": ["tenant"], - "compute.image_ssh_user": ["rhel", "cirros"], - "network-feature-enabled.api_extensions": remove_exts - } - ) - self.conf = self._get_conf("v2.0", "v3") - self.conf.set("compute", "image_ssh_user", "cirros") - self.conf.set("network-feature-enabled", "api_extensions", api_exts) - self.conf.remove_values(args) - self.assertFalse(self.conf.has_option("identity", "username")) - self.assertTrue(self.conf.has_option("identity", "tenant_name")) - self.assertFalse(self.conf.has_option("compute", "image_ssh_user")) - conf_exts = self.conf.get("network-feature-enabled", "api_extensions") - conf_exts = conf_exts.split(',') - for ext in api_exts.split(','): - if ext in remove_exts: - self.assertFalse(ext in conf_exts) - else: - self.assertTrue(ext in conf_exts) - - def test_remove_values_having_hyphen(self): - api_exts = "dvr, l3-flavors, rbac-policies, project-id" - remove_exts = ["dvr", "project-id"] - args = Namespace( - remove={ - "network-feature-enabled.api-extensions": remove_exts - } - ) - self.conf = self._get_conf("v2.0", "v3") - self.conf.set("network-feature-enabled", "api-extensions", api_exts) - self.conf.remove_values(args) - conf_exts = self.conf.get("network-feature-enabled", "api-extensions") - conf_exts = conf_exts.split(',') - for ext in api_exts.split(','): - if ext in remove_exts: - self.assertFalse(ext in conf_exts) - else: - self.assertTrue(ext in conf_exts) - - @mock.patch('config_tempest.config_tempest.LOG') - def test_remove_not_defined_values(self, mock_logging): - self.conf.remove_values(Namespace(remove={"notExistSection.key": []})) - # check if LOG.error was called - self.assertTrue(mock_logging.error.called) - self.conf.remove_values(Namespace(remove={"section.notExistKey": []})) - # check if LOG.error was called - self.assertTrue(mock_logging.error.called) - - class TestConfigTempest(BaseConfigTempestTest): FAKE_SERVICES = { @@ -494,7 +400,7 @@ class TestFlavors(BaseConfigTempestTest): self.client = self._get_clients(self.conf).flavors def _mock_create_tempest_flavor(self, mock_function): - func2mock = 'config_tempest.config_tempest.find_or_create_flavor' + func2mock = 'config_tempest.main.find_or_create_flavor' self.useFixture(MonkeyPatch(func2mock, mock_function)) tool.create_tempest_flavors(client=self.client, conf=self.conf, diff --git a/config_tempest/tests/test_config_tempest_image.py b/config_tempest/tests/test_config_tempest_image.py index 0abab09c..b473acc7 100644 --- a/config_tempest/tests/test_config_tempest_image.py +++ b/config_tempest/tests/test_config_tempest_image.py @@ -15,11 +15,12 @@ # License for the specific language governing permissions and limitations # under the License. -from config_tempest import config_tempest as tool -from config_tempest.tests.base import BaseConfigTempestTest from fixtures import MonkeyPatch import mock +from config_tempest import main as tool +from config_tempest.tests.base import BaseConfigTempestTest + class TestCreateTempestImages(BaseConfigTempestTest): @@ -33,7 +34,7 @@ class TestCreateTempestImages(BaseConfigTempestTest): self.dir = "/img/" self.conf.set("scenario", "img_dir", self.dir) - @mock.patch('config_tempest.config_tempest.find_or_upload_image') + @mock.patch('config_tempest.main.find_or_upload_image') def test_create_tempest_images_exception(self, mock_find_upload): mock_find_upload.side_effect = Exception exc = Exception @@ -45,7 +46,7 @@ class TestCreateTempestImages(BaseConfigTempestTest): allow_creation=self.allow_creation, disk_format=self.disk_format) - @mock.patch('config_tempest.config_tempest.find_or_upload_image') + @mock.patch('config_tempest.main.find_or_upload_image') def _test_create_tempest_images(self, mock_find_upload): mock_find_upload.side_effect = ["id_c", "id_d"] tool.create_tempest_images(client=self.client, @@ -127,7 +128,7 @@ class TestFindOrUploadImage(BaseConfigTempestTest): conf = self._get_conf("v2.0", "v3") self.client = self._get_clients(conf).images - @mock.patch('config_tempest.config_tempest._find_image') + @mock.patch('config_tempest.main._find_image') def test_find_or_upload_image_not_found_creation_not_allowed( self, mock_find_image): mock_find_image.return_value = None @@ -136,9 +137,9 @@ class TestFindOrUploadImage(BaseConfigTempestTest): image_id=None, image_name=None, allow_creation=False) - @mock.patch('config_tempest.config_tempest._find_image') - @mock.patch('config_tempest.config_tempest._download_file') - @mock.patch('config_tempest.config_tempest._upload_image') + @mock.patch('config_tempest.main._find_image') + @mock.patch('config_tempest.main._download_file') + @mock.patch('config_tempest.main._upload_image') def _test_find_or_upload_image_not_found_creation_allowed_format( self, mock_upload_image, mock_download_file, mock_find_image, format): @@ -167,9 +168,9 @@ class TestFindOrUploadImage(BaseConfigTempestTest): format="https") @mock.patch('shutil.copyfile') - @mock.patch('config_tempest.config_tempest._find_image') - @mock.patch('config_tempest.config_tempest._download_file') - @mock.patch('config_tempest.config_tempest._upload_image') + @mock.patch('config_tempest.main._find_image') + @mock.patch('config_tempest.main._download_file') + @mock.patch('config_tempest.main._upload_image') def test_find_or_upload_image_not_found_creation_allowed_ftp_old( self, mock_upload_image, mock_download_file, mock_find_image, mock_copy): @@ -190,7 +191,7 @@ class TestFindOrUploadImage(BaseConfigTempestTest): self.assertEqual(image_id, "my_fake_id") @mock.patch('os.path.isfile') - @mock.patch('config_tempest.config_tempest._find_image') + @mock.patch('config_tempest.main._find_image') def test_find_or_upload_image_found_downloaded( self, mock_find_image, mock_isfile): mock_find_image.return_value = \ @@ -201,9 +202,9 @@ class TestFindOrUploadImage(BaseConfigTempestTest): image_name=None, allow_creation=True) self.assertEqual(image_id, "my_fake_id") - @mock.patch('config_tempest.config_tempest._download_image') + @mock.patch('config_tempest.main._download_image') @mock.patch('os.path.isfile') - @mock.patch('config_tempest.config_tempest._find_image') + @mock.patch('config_tempest.main._find_image') def test_find_or_upload_image_found_not_downloaded( self, mock_find_image, mock_isfile, mock_download_image): image_id = "my_fake_id" diff --git a/config_tempest/tests/test_config_tempest_network.py b/config_tempest/tests/test_config_tempest_network.py index 3f83d734..aa7b81e5 100644 --- a/config_tempest/tests/test_config_tempest_network.py +++ b/config_tempest/tests/test_config_tempest_network.py @@ -15,11 +15,12 @@ # License for the specific language governing permissions and limitations # under the License. -from config_tempest import config_tempest as tool -from config_tempest.tests.base import BaseConfigTempestTest from fixtures import MonkeyPatch import mock +from config_tempest import main as tool +from config_tempest.tests.base import BaseConfigTempestTest + class TestCreateTempestNetworks(BaseConfigTempestTest): @@ -92,7 +93,7 @@ class TestCreateTempestNetworks(BaseConfigTempestTest): self.assertEqual(self.conf.get('network', 'floating_network_name'), 'tempest-network') - @mock.patch('config_tempest.config_tempest.LOG') + @mock.patch('config_tempest.main.LOG') def test_create_network_auto_discover_not_found(self, mock_logging): neutron_client = self.clients.get_neutron_client() # delete subnets => network will not be found diff --git a/config_tempest/tests/test_config_tempest_user.py b/config_tempest/tests/test_config_tempest_user.py index 60510b69..0e563bcc 100644 --- a/config_tempest/tests/test_config_tempest_user.py +++ b/config_tempest/tests/test_config_tempest_user.py @@ -15,11 +15,12 @@ # License for the specific language governing permissions and limitations # under the License. -from config_tempest import config_tempest as tool -from config_tempest.tests.base import BaseConfigTempestTest import mock from tempest.lib import exceptions +from config_tempest import main as tool +from config_tempest.tests.base import BaseConfigTempestTest + class TestCreateTempestUser(BaseConfigTempestTest): @@ -30,9 +31,8 @@ class TestCreateTempestUser(BaseConfigTempestTest): self.users_client = self._get_clients(self.conf).users self.roles_client = self._get_clients(self.conf).roles - @mock.patch('config_tempest.config_tempest.' - 'create_user_with_tenant') - @mock.patch('config_tempest.config_tempest.give_role_to_user') + @mock.patch('config_tempest.main.create_user_with_tenant') + @mock.patch('config_tempest.main.give_role_to_user') def _test_create_tempest_user(self, mock_give_role_to_user, mock_create_user_with_tenant, @@ -110,9 +110,8 @@ class TestCreateUserWithTenant(BaseConfigTempestTest): self.tenant_description = "Tenant for Tempest %s user" % self.username self.email = "%s@test.com" % self.username - @mock.patch('config_tempest.config_tempest.ProjectsClient' - '.get_project_by_name') - @mock.patch('config_tempest.config_tempest.ProjectsClient.create_project') + @mock.patch('config_tempest.main.ProjectsClient.get_project_by_name') + @mock.patch('config_tempest.main.ProjectsClient.create_project') @mock.patch('tempest.lib.services.identity.v2.users_client.' 'UsersClient.create_user') def test_create_user_with_tenant(self, @@ -133,9 +132,8 @@ class TestCreateUserWithTenant(BaseConfigTempestTest): tenantId="fake-id", email=self.email) - @mock.patch('config_tempest.config_tempest.ProjectsClient' - '.get_project_by_name') - @mock.patch('config_tempest.config_tempest.ProjectsClient.create_project') + @mock.patch('config_tempest.main.ProjectsClient.get_project_by_name') + @mock.patch('config_tempest.main.ProjectsClient.create_project') @mock.patch('tempest.lib.services.identity.v2' '.users_client.UsersClient.create_user') def test_create_user_with_tenant_tenant_exists( @@ -163,8 +161,7 @@ class TestCreateUserWithTenant(BaseConfigTempestTest): @mock.patch('tempest.lib.services.identity.v2.' 'users_client.UsersClient.update_user_password') @mock.patch('tempest.common.identity.get_user_by_username') - @mock.patch('config_tempest.config_tempest.ProjectsClient.' - 'get_project_by_name') + @mock.patch('config_tempest.main.ProjectsClient.get_project_by_name') @mock.patch('tempest.lib.services.identity.v2.' 'tenants_client.TenantsClient.create_tenant') @mock.patch('tempest.lib.services.identity.' @@ -194,9 +191,8 @@ class TestCreateUserWithTenant(BaseConfigTempestTest): @mock.patch('tempest.lib.services.identity.v2.' 'users_client.UsersClient.update_user_password') @mock.patch('tempest.common.identity.get_user_by_username') - @mock.patch('config_tempest.config_tempest.ProjectsClient.' - 'get_project_by_name') - @mock.patch('config_tempest.config_tempest.ProjectsClient.create_project') + @mock.patch('config_tempest.main.ProjectsClient.get_project_by_name') + @mock.patch('config_tempest.main.ProjectsClient.create_project') @mock.patch('tempest.lib.services.identity.v2.' 'users_client.UsersClient.create_user') def test_create_user_with_tenant_exists_user_exists( @@ -245,8 +241,7 @@ class TestGiveRoleToUser(BaseConfigTempestTest): {'name': "fake_role2", 'id': "fake_role_id2"}]} - @mock.patch('config_tempest.config_tempest.ProjectsClient.' - 'get_project_by_name') + @mock.patch('config_tempest.main.ProjectsClient.get_project_by_name') @mock.patch('tempest.lib.services.identity.v2.' 'users_client.UsersClient.list_users') @mock.patch('tempest.lib.services.identity.v2.' @@ -276,8 +271,7 @@ class TestGiveRoleToUser(BaseConfigTempestTest): mock_create_user_role_on_project.assert_called_with( "fake_tenant_id", "fake_user_id", "fake_role_id") - @mock.patch('config_tempest.config_tempest.ProjectsClient.' - 'get_project_by_name') + @mock.patch('config_tempest.main.ProjectsClient.get_project_by_name') @mock.patch('tempest.lib.services.identity.' 'v2.users_client.UsersClient.list_users') @mock.patch('tempest.lib.services.identity.v2.' @@ -308,8 +302,7 @@ class TestGiveRoleToUser(BaseConfigTempestTest): tenant_name=self.tenant_name, role_name=role_name) - @mock.patch('config_tempest.config_tempest.ProjectsClient.' - 'get_project_by_name') + @mock.patch('config_tempest.main.ProjectsClient.get_project_by_name') @mock.patch('tempest.lib.services.identity.v2.' 'users_client.UsersClient.list_users') @mock.patch('tempest.lib.services.identity.v2.' @@ -339,8 +332,7 @@ class TestGiveRoleToUser(BaseConfigTempestTest): role_name=self.role_name, role_required=False) - @mock.patch('config_tempest.config_tempest.ProjectsClient' - '.get_project_by_name') + @mock.patch('config_tempest.main.ProjectsClient.get_project_by_name') @mock.patch('tempest.lib.services.identity.v2.' 'users_client.UsersClient.list_users') @mock.patch('tempest.lib.services.identity.v2.' diff --git a/config_tempest/tests/test_tempest_conf.py b/config_tempest/tests/test_tempest_conf.py new file mode 100644 index 00000000..978e7171 --- /dev/null +++ b/config_tempest/tests/test_tempest_conf.py @@ -0,0 +1,112 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 Red Hat, Inc. +# 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 mock + +from config_tempest import tempest_conf +from config_tempest.tests.base import BaseConfigTempestTest + + +class TestTempestConf(BaseConfigTempestTest): + def setUp(self): + super(TestTempestConf, self).setUp() + self.conf = tempest_conf.TempestConf() + + def test_set_value(self): + resp = self.conf.set("section", "key", "value") + self.assertTrue(resp) + self.assertEqual(self.conf.get("section", "key"), "value") + self.assertEqual(self.conf.get_defaulted("section", "key"), "value") + + def test_set_value_overwrite(self): + # set value wihout priority (default: priority=False) + resp = self.conf.set("section", "key", "value") + # value should be overwritten, because it wasn't set with priority + resp = self.conf.set("section", "key", "value") + self.assertTrue(resp) + + def test_set_value_overwrite_priority(self): + resp = self.conf.set("sectionPriority", "key", "value", priority=True) + resp = self.conf.set("sectionPriority", "key", "value") + self.assertFalse(resp) + + def test_set_value_overwrite_by_priority(self): + resp = self.conf.set("section", "key", "value") + resp = self.conf.set("section", "key", "value", priority=True) + self.assertTrue(resp) + + def test_set_value_overwrite_priority_by_priority(self): + resp = self.conf.set("sectionPriority", "key", "value", priority=True) + resp = self.conf.set("sectionPriority", "key", "value", priority=True) + self.assertTrue(resp) + + def test_get_bool_value(self): + self.assertTrue(self.conf.get_bool_value("True")) + self.assertFalse(self.conf.get_bool_value("False")) + self.assertRaises(ValueError, self.conf.get_bool_value, "no") + + def test_remove_values(self): + api_exts = "router_availability_zone,rbac-policies,pagination,sorting," + api_exts += "standard-attr-description,router,binding,metering," + api_exts += "allowed-address-pairs,project-id,dvr,l3-flavors,tag-ext" + remove_exts = ["router", "project-id", "dvr"] + remove = { + "identity.username": ["demo"], + "identity.tenant_name": ["tenant"], + "compute.image_ssh_user": ["rhel", "cirros"], + "network-feature-enabled.api_extensions": remove_exts + } + self.conf = self._get_conf("v2.0", "v3") + self.conf.set("compute", "image_ssh_user", "cirros") + self.conf.set("network-feature-enabled", "api_extensions", api_exts) + self.conf.remove_values(remove) + self.assertFalse(self.conf.has_option("identity", "username")) + self.assertTrue(self.conf.has_option("identity", "tenant_name")) + self.assertFalse(self.conf.has_option("compute", "image_ssh_user")) + conf_exts = self.conf.get("network-feature-enabled", "api_extensions") + conf_exts = conf_exts.split(',') + for ext in api_exts.split(','): + if ext in remove_exts: + self.assertFalse(ext in conf_exts) + else: + self.assertTrue(ext in conf_exts) + + def test_remove_values_having_hyphen(self): + api_exts = "dvr, l3-flavors, rbac-policies, project-id" + remove_exts = ["dvr", "project-id"] + remove = { + "network-feature-enabled.api-extensions": remove_exts + } + self.conf = self._get_conf("v2.0", "v3") + self.conf.set("network-feature-enabled", "api-extensions", api_exts) + self.conf.remove_values(remove) + conf_exts = self.conf.get("network-feature-enabled", "api-extensions") + conf_exts = conf_exts.split(',') + for ext in api_exts.split(','): + if ext in remove_exts: + self.assertFalse(ext in conf_exts) + else: + self.assertTrue(ext in conf_exts) + + @mock.patch('config_tempest.tempest_conf.LOG') + def test_remove_not_defined_values(self, mock_logging): + self.conf.remove_values({"notExistSection.key": []}) + # check if LOG.error was called + self.assertTrue(mock_logging.error.called) + self.conf.remove_values({"section.notExistKey": []}) + # check if LOG.error was called + self.assertTrue(mock_logging.error.called) diff --git a/setup.cfg b/setup.cfg index 2976e589..ea01d66b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -28,7 +28,7 @@ data_files = [entry_points] console_scripts = - discover-tempest-config = config_tempest.config_tempest:main + discover-tempest-config = config_tempest.main:main [build_sphinx] source-dir = doc/source