
The tests were modifying a global ConfigOpts object, without resetting the old value, which could affect other tests as well. The new ConfPatcher class can be used both as a context manager and as a decorator, making sure that the old value of configuration option is set back after exiting from the decorated function or from the context manager. Change-Id: If23bf225207977e0e313dc806d53bca8a40215d6
148 lines
4.3 KiB
Python
148 lines
4.3 KiB
Python
# Copyright 2014 Cloudbase Solutions Srl
|
|
#
|
|
# 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 contextlib
|
|
import functools
|
|
import logging as base_logging
|
|
import os
|
|
import shutil
|
|
import tempfile
|
|
|
|
from oslo.config import cfg
|
|
|
|
from cloudbaseinit.openstack.common import log as logging
|
|
|
|
|
|
CONF = cfg.CONF
|
|
|
|
__all__ = (
|
|
'create_tempfile',
|
|
'create_tempdir',
|
|
'LogSnatcher',
|
|
'ConfPatcher',
|
|
)
|
|
|
|
|
|
@contextlib.contextmanager
|
|
def create_tempdir():
|
|
"""Create a temporary directory.
|
|
|
|
This is a context manager, which creates a new temporary
|
|
directory and removes it when exiting from the context manager
|
|
block.
|
|
"""
|
|
tempdir = tempfile.mkdtemp(prefix="cloudbaseinit-tests")
|
|
try:
|
|
yield tempdir
|
|
finally:
|
|
shutil.rmtree(tempdir)
|
|
|
|
|
|
@contextlib.contextmanager
|
|
def create_tempfile(content=None):
|
|
"""Create a temporary file.
|
|
|
|
This is a context manager, which uses `create_tempdir` to obtain a
|
|
temporary directory, where the file will be placed.
|
|
|
|
:param content:
|
|
Additionally, a string which will be written
|
|
in the new file.
|
|
"""
|
|
with create_tempdir() as temp:
|
|
fd, path = tempfile.mkstemp(dir=temp)
|
|
os.close(fd)
|
|
if content:
|
|
with open(path, 'w') as stream:
|
|
stream.write(content)
|
|
yield path
|
|
|
|
|
|
# This is similar with unittest.TestCase.assertLogs from Python 3.4.
|
|
class SnatchHandler(base_logging.Handler):
|
|
def __init__(self, *args, **kwargs):
|
|
super(SnatchHandler, self).__init__(*args, **kwargs)
|
|
self.output = []
|
|
|
|
def emit(self, record):
|
|
msg = self.format(record)
|
|
self.output.append(msg)
|
|
|
|
|
|
class LogSnatcher(object):
|
|
"""A context manager to capture emitted logged messages.
|
|
|
|
The class can be used as following::
|
|
|
|
with LogSnatcher('plugins.windows.createuser') as snatcher:
|
|
LOG.info("doing stuff")
|
|
LOG.info("doing stuff %s", 1)
|
|
LOG.warn("doing other stuff")
|
|
...
|
|
self.assertEqual(snatcher.output,
|
|
['INFO:unknown:doing stuff',
|
|
'INFO:unknown:doing stuff 1',
|
|
'WARN:unknown:doing other stuff'])
|
|
"""
|
|
|
|
@property
|
|
def output(self):
|
|
return self._snatch_handler.output
|
|
|
|
def __init__(self, logger_name):
|
|
self._logger_name = logger_name
|
|
self._snatch_handler = SnatchHandler()
|
|
self._logger = logging.getLogger(self._logger_name)
|
|
self._previous_level = self._logger.logger.getEffectiveLevel()
|
|
|
|
def __enter__(self):
|
|
self._logger.logger.setLevel(base_logging.DEBUG)
|
|
self._logger.handlers.append(self._snatch_handler)
|
|
return self
|
|
|
|
def __exit__(self, *args):
|
|
self._logger.handlers.remove(self._snatch_handler)
|
|
self._logger.logger.setLevel(self._previous_level)
|
|
|
|
|
|
class ConfPatcher(object):
|
|
"""Override the configuration for the given key, with the given value.
|
|
|
|
This class can be used both as a context manager and as a decorator.
|
|
"""
|
|
# TODO(cpopa): mock.patch.dict would have been a better solution
|
|
# but oslo.config.cfg doesn't support item
|
|
# assignment.
|
|
|
|
def __init__(self, key, value, conf=CONF):
|
|
self._original_value = conf.get(key)
|
|
self._key = key
|
|
self._value = value
|
|
self._conf = conf
|
|
|
|
def __call__(self, func, *args, **kwargs):
|
|
def _wrapped_f(*args, **kwargs):
|
|
with self:
|
|
return func(*args, **kwargs)
|
|
|
|
functools.update_wrapper(_wrapped_f, func)
|
|
return _wrapped_f
|
|
|
|
def __enter__(self):
|
|
self._conf.set_override(self._key, self._value)
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
self._conf.set_override(self._key, self._original_value)
|