59e647f82c
When we call oslo.config.cfg.CONF(), it will do basic setup and search configuration files under certain directories, by default, they are [/etc, /etc/ceilometer, ~/, ~/.ceilometer]. However, we should avoid such behaviour when we run unit test code, because that if the system has run devstack or installed ceilometer services, then /etc/ceilometer/ceilometer.conf will exist, then unit test result can be different. So we should mock the default searching directories of cfg in the begining of all unit tests, which will call cfg.CONF() at somewhere during the test. The best place to mock the default directories can be ceilometer.test.base.BaseTestCase, which should be used as parent class of all other test classes. Note: since this patch sets default searching directory to {repo}/etc/ceilometer, you can run the unit test with different settings which are set in etc/ceilometer/ceilometer.conf (not tracked by git). Note: mock.patch.stopall has compatibility problem with oslo.fixture, so this patch slightly refactors the tests.compute.pollsters.base.TestPollsterBase.setUp method. Change-Id: I533ffb2ba2c9be0223cecbcf04176312e4a96369 Closes-Bug: #1328550
123 lines
4.1 KiB
Python
123 lines
4.1 KiB
Python
#!/usr/bin/env python
|
|
#
|
|
# Copyright 2012 New Dream Network (DreamHost)
|
|
#
|
|
# Author: Doug Hellmann <doug.hellmann@dreamhost.com>
|
|
#
|
|
# 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.
|
|
"""Test base classes.
|
|
"""
|
|
import functools
|
|
import os.path
|
|
import six
|
|
|
|
import eventlet
|
|
import oslo.messaging
|
|
from testtools import testcase
|
|
|
|
from ceilometer import messaging
|
|
from ceilometer.openstack.common.fixture import mockpatch
|
|
from ceilometer.openstack.common import test
|
|
from ceilometer.openstack.common import timeutils
|
|
|
|
|
|
class BaseTestCase(test.BaseTestCase):
|
|
def setup_messaging(self, conf, exchange=None):
|
|
self.useFixture(oslo.messaging.conffixture.ConfFixture(conf))
|
|
conf.set_override("notification_driver", "messaging")
|
|
if not exchange:
|
|
exchange = 'ceilometer'
|
|
conf.set_override("control_exchange", exchange)
|
|
|
|
# NOTE(sileht): oslo.messaging fake driver uses time.sleep
|
|
# for task switch, so we need to monkey_patch it
|
|
# and also ensure the correct exchange have been set
|
|
eventlet.monkey_patch(time=True)
|
|
|
|
# NOTE(sileht): Ensure a new oslo.messaging driver is loaded
|
|
# between each tests
|
|
self.transport = messaging.get_transport("fake://", cache=False)
|
|
self.useFixture(mockpatch.Patch(
|
|
'ceilometer.messaging.get_transport',
|
|
return_value=self.transport))
|
|
|
|
def setUp(self):
|
|
super(BaseTestCase, self).setUp()
|
|
self.useFixture(mockpatch.Patch(
|
|
'oslo.config.cfg._get_config_dirs',
|
|
return_value=[self.path_get('etc/ceilometer')]))
|
|
|
|
def assertTimestampEqual(self, first, second, msg=None):
|
|
"""Checks that two timestamps are equals.
|
|
|
|
This relies on assertAlmostEqual to avoid rounding problem, and only
|
|
checks up the first microsecond values.
|
|
|
|
"""
|
|
return self.assertAlmostEqual(
|
|
timeutils.delta_seconds(first, second),
|
|
0.0,
|
|
places=5)
|
|
|
|
def assertIsEmpty(self, obj):
|
|
try:
|
|
if len(obj) != 0:
|
|
self.fail("%s is not empty" % type(obj))
|
|
except (TypeError, AttributeError):
|
|
self.fail("%s doesn't have length" % type(obj))
|
|
|
|
def assertIsNotEmpty(self, obj):
|
|
try:
|
|
if len(obj) == 0:
|
|
self.fail("%s is empty" % type(obj))
|
|
except (TypeError, AttributeError):
|
|
self.fail("%s doesn't have length" % type(obj))
|
|
|
|
@staticmethod
|
|
def path_get(project_file=None):
|
|
root = os.path.abspath(os.path.join(os.path.dirname(__file__),
|
|
'..',
|
|
'..',
|
|
)
|
|
)
|
|
if project_file:
|
|
return os.path.join(root, project_file)
|
|
else:
|
|
return root
|
|
|
|
|
|
def _skip_decorator(func):
|
|
@functools.wraps(func)
|
|
def skip_if_not_implemented(*args, **kwargs):
|
|
try:
|
|
return func(*args, **kwargs)
|
|
except AssertionError:
|
|
raise
|
|
except NotImplementedError as e:
|
|
raise testcase.TestSkipped(six.text_type(e))
|
|
except Exception as e:
|
|
if 'not implemented' in six.text_type(e):
|
|
raise testcase.TestSkipped(six.text_type(e))
|
|
raise
|
|
return skip_if_not_implemented
|
|
|
|
|
|
class SkipNotImplementedMeta(type):
|
|
def __new__(cls, name, bases, local):
|
|
for attr in local:
|
|
value = local[attr]
|
|
if callable(value) and (
|
|
attr.startswith('test_') or attr == 'setUp'):
|
|
local[attr] = _skip_decorator(value)
|
|
return type.__new__(cls, name, bases, local)
|