# # Copyright 2013 Mirantis, Inc. # Copyright 2013 OpenStack Foundation # 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 fixtures from oslo_config import cfg class Config(fixtures.Fixture): """Allows overriding configuration settings for the test. `conf` will be reset on cleanup. """ def __init__(self, conf=cfg.CONF): self.conf = conf def setUp(self): super(Config, self).setUp() # NOTE(morganfainberg): unregister must be added to cleanup before # reset is because cleanup works in reverse order of registered items, # and a reset must occur before unregistering options can occur. self.addCleanup(self._reset_default_config_files) self.addCleanup(self._reset_default_config_dirs) self.addCleanup(self._unregister_config_opts) self.addCleanup(self.conf.reset) self._registered_config_opts = {} # Grab an old copy of the default config files/dirs - if it exists - # for subsequent cleanup. if hasattr(self.conf, 'default_config_files'): self._default_config_files = self.conf.default_config_files else: self._default_config_files = None if hasattr(self.conf, 'default_config_dirs'): self._default_config_dirs = self.conf.default_config_dirs else: self._default_config_dirs = None def config(self, **kw): """Override configuration values. The keyword arguments are the names of configuration options to override and their values. If a `group` argument is supplied, the overrides are applied to the specified configuration option group, otherwise the overrides are applied to the ``default`` group. If a `enforce_type` is supplied, will convert the override value to the option's type before overriding. """ group = kw.pop('group', None) enforce_type = kw.pop('enforce_type', True) for k, v in kw.items(): if enforce_type is False: self.conf.set_override(k, v, group, enforce_type=False) else: # this removes the deprecation warning if you are just # using defaults self.conf.set_override(k, v, group) def _unregister_config_opts(self): for group in self._registered_config_opts: self.conf.unregister_opts(self._registered_config_opts[group], group=group) def _reset_default_config_files(self): if not hasattr(self.conf, 'default_config_files'): return if self._default_config_files: self.conf.default_config_files = self._default_config_files else: # Delete, because we could conceivably begin with the property # being unset. self.conf.default_config_files = None def _reset_default_config_dirs(self): if not hasattr(self.conf, 'default_config_dirs'): return if self._default_config_dirs: self.conf.default_config_dirs = self._default_config_dirs else: # Delete, because we could conceivably begin with the property # being unset. self.conf.default_config_dirs = None def register_opt(self, opt, group=None): """Register a single option for the test run. Options registered in this manner will automatically be unregistered during cleanup. If a `group` argument is supplied, it will register the new option to that group, otherwise the option is registered to the ``default`` group. """ self.conf.register_opt(opt, group=group) self._registered_config_opts.setdefault(group, set()).add(opt) def register_opts(self, opts, group=None): """Register multiple options for the test run. This works in the same manner as register_opt() but takes a list of options as the first argument. All arguments will be registered to the same group if the ``group`` argument is supplied, otherwise all options will be registered to the ``default`` group. """ for opt in opts: self.register_opt(opt, group=group) def register_cli_opt(self, opt, group=None): """Register a single CLI option for the test run. Options registered in this manner will automatically be unregistered during cleanup. If a `group` argument is supplied, it will register the new option to that group, otherwise the option is registered to the ``default`` group. CLI options must be registered before the command line and config files are parsed. This is to ensure that all CLI options are shown in --help and option validation works as expected. """ self.conf.register_cli_opt(opt, group=group) self._registered_config_opts.setdefault(group, set()).add(opt) def register_cli_opts(self, opts, group=None): """Register multiple CLI options for the test run. This works in the same manner as register_opt() but takes a list of options as the first argument. All arguments will be registered to the same group if the ``group`` argument is supplied, otherwise all options will be registered to the ``default`` group. CLI options must be registered before the command line and config files are parsed. This is to ensure that all CLI options are shown in --help and option validation works as expected. """ for opt in opts: self.register_cli_opt(opt, group=group) def load_raw_values(self, group=None, **kwargs): """Load raw values into the configuration without registering them. This method adds a series of parameters into the current config instance, as if they had been loaded by a ConfigParser. This method does not require that you register the configuration options first, however the values loaded will not be accessible until you do. """ # Make sure the namespace exists for our tests. if not self.conf._namespace: self.conf.__call__(args=[]) # Default out the group name group = 'DEFAULT' if not group else group raw_config = dict() raw_config[group] = dict() for key, value in kwargs.items(): # Parsed values are an array of raw strings. raw_config[group][key] = [str(value)] self.conf._namespace._add_parsed_config_file(raw_config, raw_config) def set_config_files(self, config_files): """Specify a list of config files to read. This method allows you to predefine the list of configuration files that are loaded by oslo_config. It will ensure that your tests do not attempt to autodetect, and accidentally pick up config files from locally installed services. """ if not isinstance(config_files, list): raise AttributeError("Please pass a list() to set_config_files()") # Make sure the namespace exists for our tests. if not self.conf._namespace: self.conf.__call__(args=[]) self.conf.default_config_files = config_files self.conf.reload_config_files() def set_config_dirs(self, config_dirs): """Specify a list of config dirs to read. This method allows you to predefine the list of configuration dirs that are loaded by oslo_config. It will ensure that your tests do not attempt to autodetect, and accidentally pick up config files from locally installed services. """ if not isinstance(config_dirs, list): raise AttributeError("Please pass a list() to set_config_dirs()") # Make sure the namespace exists for our tests. if not self.conf._namespace: self.conf([]) self.conf.default_config_dirs = config_dirs self.conf.reload_config_files() def set_default(self, name, default, group=None): """Set a default value for an option. This method is not necessarily meant to be invoked directly. It is here to allow the set_defaults() functions in various Oslo libraries to work with a Config fixture instead of a ConfigOpts instance. Use it like:: class MyTest(testtools.TestCase): def setUp(self): super(MyTest, self).setUp() self.conf = self.useFixture(fixture.Config()) def test_something(self): some_library.set_defaults(self.conf, name='value') some_library.do_something_exciting() """ self.conf.set_default(name, default, group) self.addCleanup(self.conf.clear_default, name, group)