summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--.testr.conf4
-rw-r--r--designate.sublime-project1
-rw-r--r--designate/openstack/common/fileutils.py139
-rw-r--r--designate/openstack/common/fixture/__init__.py0
-rw-r--r--designate/openstack/common/fixture/config.py46
-rw-r--r--designate/openstack/common/fixture/lockutils.py53
-rw-r--r--designate/openstack/common/fixture/mockpatch.py51
-rw-r--r--designate/openstack/common/fixture/moxstubout.py34
-rw-r--r--designate/openstack/common/lockutils.py305
-rw-r--r--designate/openstack/common/test.py53
-rw-r--r--designate/tests/__init__.py61
-rw-r--r--designate/tests/test_agent/__init__.py2
-rw-r--r--designate/tests/test_agent/test_service.py2
-rw-r--r--designate/tests/test_api/__init__.py2
-rw-r--r--designate/tests/test_api/test_middleware.py6
-rw-r--r--designate/tests/test_api/test_service.py2
-rw-r--r--designate/tests/test_api/test_v1/__init__.py2
-rw-r--r--designate/tests/test_api/test_v1/test_domains.py2
-rw-r--r--designate/tests/test_api/test_v1/test_records.py2
-rw-r--r--designate/tests/test_api/test_v1/test_servers.py2
-rw-r--r--designate/tests/test_api/test_v2/__init__.py2
-rw-r--r--designate/tests/test_api/test_v2/test_limits.py2
-rw-r--r--designate/tests/test_api/test_v2/test_zones.py2
-rw-r--r--designate/tests/test_backend/__init__.py2
-rw-r--r--designate/tests/test_backend/test_bind9.py2
-rw-r--r--designate/tests/test_backend/test_dnsmasq.py2
-rw-r--r--designate/tests/test_backend/test_fake.py2
-rw-r--r--designate/tests/test_backend/test_mysqlbind9.py2
-rw-r--r--designate/tests/test_backend/test_powerdns.py2
-rw-r--r--designate/tests/test_central/__init__.py2
-rw-r--r--designate/tests/test_central/test_service.py74
-rw-r--r--designate/tests/test_notification_handler/__init__.py9
-rw-r--r--designate/tests/test_notification_handler/test_nova.py4
-rw-r--r--designate/tests/test_notification_handler/test_quantum.py4
-rw-r--r--designate/tests/test_quota/__init__.py21
-rw-r--r--designate/tests/test_quota/test_noop.py2
-rw-r--r--designate/tests/test_quota/test_storage.py18
-rw-r--r--designate/tests/test_resources/test_schemas/test_v2.py13
-rw-r--r--designate/tests/test_storage/__init__.py88
-rw-r--r--designate/tests/test_storage/test_api.py79
-rw-r--r--designate/tests/test_storage/test_sqlalchemy.py9
-rw-r--r--designate/tests/test_utils.py7
-rw-r--r--openstack-common.conf1
-rw-r--r--test-requirements.txt12
-rw-r--r--tox.ini14
46 files changed, 906 insertions, 239 deletions
diff --git a/.gitignore b/.gitignore
index d0bca832..9ed6b9e5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,3 +23,4 @@ designate/versioninfo
*.DS_Store
*.idea
/bind9
+.testrepository/*
diff --git a/.testr.conf b/.testr.conf
new file mode 100644
index 00000000..60477e87
--- /dev/null
+++ b/.testr.conf
@@ -0,0 +1,4 @@
+[DEFAULT]
+test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} ${PYTHON:-python} -m subunit.run discover -t ./ ./ $LISTOPT $IDOPTION
+test_id_option=--load-list $IDFILE
+test_list_option=--list
diff --git a/designate.sublime-project b/designate.sublime-project
index 87c97554..dffc7884 100644
--- a/designate.sublime-project
+++ b/designate.sublime-project
@@ -24,7 +24,6 @@
"*.psd",
"*.db",
".vagrant",
- ".noseids"
],
"folder_exclude_patterns":
[
diff --git a/designate/openstack/common/fileutils.py b/designate/openstack/common/fileutils.py
new file mode 100644
index 00000000..8fb7c285
--- /dev/null
+++ b/designate/openstack/common/fileutils.py
@@ -0,0 +1,139 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 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 contextlib
+import errno
+import os
+import tempfile
+
+from designate.openstack.common import excutils
+from designate.openstack.common.gettextutils import _ # noqa
+from designate.openstack.common import log as logging
+
+LOG = logging.getLogger(__name__)
+
+_FILE_CACHE = {}
+
+
+def ensure_tree(path):
+ """Create a directory (and any ancestor directories required)
+
+ :param path: Directory to create
+ """
+ try:
+ os.makedirs(path)
+ except OSError as exc:
+ if exc.errno == errno.EEXIST:
+ if not os.path.isdir(path):
+ raise
+ else:
+ raise
+
+
+def read_cached_file(filename, force_reload=False):
+ """Read from a file if it has been modified.
+
+ :param force_reload: Whether to reload the file.
+ :returns: A tuple with a boolean specifying if the data is fresh
+ or not.
+ """
+ global _FILE_CACHE
+
+ if force_reload and filename in _FILE_CACHE:
+ del _FILE_CACHE[filename]
+
+ reloaded = False
+ mtime = os.path.getmtime(filename)
+ cache_info = _FILE_CACHE.setdefault(filename, {})
+
+ if not cache_info or mtime > cache_info.get('mtime', 0):
+ LOG.debug(_("Reloading cached file %s") % filename)
+ with open(filename) as fap:
+ cache_info['data'] = fap.read()
+ cache_info['mtime'] = mtime
+ reloaded = True
+ return (reloaded, cache_info['data'])
+
+
+def delete_if_exists(path, remove=os.unlink):
+ """Delete a file, but ignore file not found error.
+
+ :param path: File to delete
+ :param remove: Optional function to remove passed path
+ """
+
+ try:
+ remove(path)
+ except OSError as e:
+ if e.errno != errno.ENOENT:
+ raise
+
+
+@contextlib.contextmanager
+def remove_path_on_error(path, remove=delete_if_exists):
+ """Protect code that wants to operate on PATH atomically.
+ Any exception will cause PATH to be removed.
+
+ :param path: File to work with
+ :param remove: Optional function to remove passed path
+ """
+
+ try:
+ yield
+ except Exception:
+ with excutils.save_and_reraise_exception():
+ remove(path)
+
+
+def file_open(*args, **kwargs):
+ """Open file
+
+ see built-in file() documentation for more details
+
+ Note: The reason this is kept in a separate module is to easily
+ be able to provide a stub module that doesn't alter system
+ state at all (for unit tests)
+ """
+ return file(*args, **kwargs)
+
+
+def write_to_tempfile(content, path=None, suffix='', prefix='tmp'):
+ """Create temporary file or use existing file.
+
+ This util is needed for creating temporary file with
+ specified content, suffix and prefix. If path is not None,
+ it will be used for writing content. If the path doesn't
+ exist it'll be created.
+
+ :param content: content for temporary file.
+ :param path: same as parameter 'dir' for mkstemp
+ :param suffix: same as parameter 'suffix' for mkstemp
+ :param prefix: same as parameter 'prefix' for mkstemp
+
+ For example: it can be used in database tests for creating
+ configuration files.
+ """
+ if path:
+ ensure_tree(path)
+
+ (fd, path) = tempfile.mkstemp(suffix=suffix, dir=path, prefix=prefix)
+ try:
+ os.write(fd, content)
+ finally:
+ os.close(fd)
+ return path
diff --git a/designate/openstack/common/fixture/__init__.py b/designate/openstack/common/fixture/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/designate/openstack/common/fixture/__init__.py
diff --git a/designate/openstack/common/fixture/config.py b/designate/openstack/common/fixture/config.py
new file mode 100644
index 00000000..93748c1c
--- /dev/null
+++ b/designate/openstack/common/fixture/config.py
@@ -0,0 +1,46 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# 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
+import six
+
+
+class Config(fixtures.Fixture):
+ """Override some 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.
+
+ All overrides are automatically cleared at the end of the current
+ test by the reset() method, which is registered by addCleanup().
+ """
+
+ def __init__(self, conf=cfg.CONF):
+ self.conf = conf
+
+ def setUp(self):
+ super(Config, self).setUp()
+ self.addCleanup(self.conf.reset)
+
+ def config(self, **kw):
+ group = kw.pop('group', None)
+ for k, v in six.iteritems(kw):
+ self.conf.set_override(k, v, group)
diff --git a/designate/openstack/common/fixture/lockutils.py b/designate/openstack/common/fixture/lockutils.py
new file mode 100644
index 00000000..2c0dd101
--- /dev/null
+++ b/designate/openstack/common/fixture/lockutils.py
@@ -0,0 +1,53 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 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 designate.openstack.common.lockutils import lock
+
+
+class LockFixture(fixtures.Fixture):
+ """External locking fixture.
+
+ This fixture is basically an alternative to the synchronized decorator with
+ the external flag so that tearDowns and addCleanups will be included in
+ the lock context for locking between tests. The fixture is recommended to
+ be the first line in a test method, like so::
+
+ def test_method(self):
+ self.useFixture(LockFixture)
+ ...
+
+ or the first line in setUp if all the test methods in the class are
+ required to be serialized. Something like::
+
+ class TestCase(testtools.testcase):
+ def setUp(self):
+ self.useFixture(LockFixture)
+ super(TestCase, self).setUp()
+ ...
+
+ This is because addCleanups are put on a LIFO queue that gets run after the
+ test method exits. (either by completing or raising an exception)
+ """
+ def __init__(self, name, lock_file_prefix=None):
+ self.mgr = lock(name, lock_file_prefix, True)
+
+ def setUp(self):
+ super(LockFixture, self).setUp()
+ self.addCleanup(self.mgr.__exit__, None, None, None)
+ self.mgr.__enter__()
diff --git a/designate/openstack/common/fixture/mockpatch.py b/designate/openstack/common/fixture/mockpatch.py
new file mode 100644
index 00000000..cd0d6ca6
--- /dev/null
+++ b/designate/openstack/common/fixture/mockpatch.py
@@ -0,0 +1,51 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# Copyright 2013 Hewlett-Packard Development Company, L.P.
+# 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
+import mock
+
+
+class PatchObject(fixtures.Fixture):
+ """Deal with code around mock."""
+
+ def __init__(self, obj, attr, **kwargs):
+ self.obj = obj
+ self.attr = attr
+ self.kwargs = kwargs
+
+ def setUp(self):
+ super(PatchObject, self).setUp()
+ _p = mock.patch.object(self.obj, self.attr, **self.kwargs)
+ self.mock = _p.start()
+ self.addCleanup(_p.stop)
+
+
+class Patch(fixtures.Fixture):
+
+ """Deal with code around mock.patch."""
+
+ def __init__(self, obj, **kwargs):
+ self.obj = obj
+ self.kwargs = kwargs
+
+ def setUp(self):
+ super(Patch, self).setUp()
+ _p = mock.patch(self.obj, **self.kwargs)
+ self.mock = _p.start()
+ self.addCleanup(_p.stop)
diff --git a/designate/openstack/common/fixture/moxstubout.py b/designate/openstack/common/fixture/moxstubout.py
new file mode 100644
index 00000000..a0e74fd1
--- /dev/null
+++ b/designate/openstack/common/fixture/moxstubout.py
@@ -0,0 +1,34 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# Copyright 2013 Hewlett-Packard Development Company, L.P.
+# 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
+import mox
+
+
+class MoxStubout(fixtures.Fixture):
+ """Deal with code around mox and stubout as a fixture."""
+
+ def setUp(self):
+ super(MoxStubout, self).setUp()
+ # emulate some of the mox stuff, we can't use the metaclass
+ # because it screws with our generators
+ self.mox = mox.Mox()
+ self.stubs = self.mox.stubs
+ self.addCleanup(self.mox.UnsetStubs)
+ self.addCleanup(self.mox.VerifyAll)
diff --git a/designate/openstack/common/lockutils.py b/designate/openstack/common/lockutils.py
new file mode 100644
index 00000000..413a7f00
--- /dev/null
+++ b/designate/openstack/common/lockutils.py
@@ -0,0 +1,305 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 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 contextlib
+import errno
+import functools
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+import threading
+import time
+import weakref
+
+from oslo.config import cfg
+
+from designate.openstack.common import fileutils
+from designate.openstack.common.gettextutils import _ # noqa
+from designate.openstack.common import local
+from designate.openstack.common import log as logging
+
+
+LOG = logging.getLogger(__name__)
+
+
+util_opts = [
+ cfg.BoolOpt('disable_process_locking', default=False,
+ help='Whether to disable inter-process locks'),
+ cfg.StrOpt('lock_path',
+ default=os.environ.get("DESIGNATE_LOCK_PATH"),
+ help=('Directory to use for lock files.'))
+]
+
+
+CONF = cfg.CONF
+CONF.register_opts(util_opts)
+
+
+def set_defaults(lock_path):
+ cfg.set_defaults(util_opts, lock_path=lock_path)
+
+
+class _InterProcessLock(object):
+ """Lock implementation which allows multiple locks, working around
+ issues like bugs.debian.org/cgi-bin/bugreport.cgi?bug=632857 and does
+ not require any cleanup. Since the lock is always held on a file
+ descriptor rather than outside of the process, the lock gets dropped
+ automatically if the process crashes, even if __exit__ is not executed.
+
+ There are no guarantees regarding usage by multiple green threads in a
+ single process here. This lock works only between processes. Exclusive
+ access between local threads should be achieved using the semaphores
+ in the @synchronized decorator.
+
+ Note these locks are released when the descriptor is closed, so it's not
+ safe to close the file descriptor while another green thread holds the
+ lock. Just opening and closing the lock file can break synchronisation,
+ so lock files must be accessed only using this abstraction.
+ """
+
+ def __init__(self, name):
+ self.lockfile = None
+ self.fname = name
+
+ def __enter__(self):
+ self.lockfile = open(self.fname, 'w')
+
+ while True:
+ try:
+ # Using non-blocking locks since green threads are not
+ # patched to deal with blocking locking calls.
+ # Also upon reading the MSDN docs for locking(), it seems
+ # to have a laughable 10 attempts "blocking" mechanism.
+ self.trylock()
+ return self
+ except IOError as e:
+ if e.errno in (errno.EACCES, errno.EAGAIN):
+ # external locks synchronise things like iptables
+ # updates - give it some time to prevent busy spinning
+ time.sleep(0.01)
+ else:
+ raise
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ try:
+ self.unlock()
+ self.lockfile.close()
+ except IOError:
+ LOG.exception(_("Could not release the acquired lock `%s`"),
+ self.fname)
+
+ def trylock(self):
+ raise NotImplementedError()
+
+ def unlock(self):
+ raise NotImplementedError()
+
+
+class _WindowsLock(_InterProcessLock):
+ def trylock(self):
+ msvcrt.locking(self.lockfile.fileno(), msvcrt.LK_NBLCK, 1)
+
+ def unlock(self):
+ msvcrt.locking(self.lockfile.fileno(), msvcrt.LK_UNLCK, 1)
+
+
+class _PosixLock(_InterProcessLock):
+ def trylock(self):
+ fcntl.lockf(self.lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB)
+
+ def unlock(self):
+ fcntl.lockf(self.lockfile, fcntl.LOCK_UN)
+
+
+if os.name == 'nt':
+ import msvcrt
+ InterProcessLock = _WindowsLock
+else:
+ import fcntl
+ InterProcessLock = _PosixLock
+
+_semaphores = weakref.WeakValueDictionary()
+_semaphores_lock = threading.Lock()
+
+
+@contextlib.contextmanager
+def lock(name, lock_file_prefix=None, external=False, lock_path=None):
+ """Context based lock
+
+ This function yields a `threading.Semaphore` instance (if we don't use
+ eventlet.monkey_patch(), else `semaphore.Semaphore`) unless external is
+ True, in which case, it'll yield an InterProcessLock instance.
+
+ :param lock_file_prefix: The lock_file_prefix argument is used to provide
+ lock files on disk with a meaningful prefix.
+
+ :param external: The external keyword argument denotes whether this lock
+ should work across multiple processes. This means that if two different
+ workers both run a a method decorated with @synchronized('mylock',
+ external=True), only one of them will execute at a time.
+
+ :param lock_path: The lock_path keyword argument is used to specify a
+ special location for external lock files to live. If nothing is set, then
+ CONF.lock_path is used as a default.
+ """
+ with _semaphores_lock:
+ try:
+ sem = _semaphores[name]
+ except KeyError:
+ sem = threading.Semaphore()
+ _semaphores[name] = sem
+
+ with sem:
+ LOG.debug(_('Got semaphore "%(lock)s"'), {'lock': name})
+
+ # NOTE(mikal): I know this looks odd
+ if not hasattr(local.strong_store, 'locks_held'):
+ local.strong_store.locks_held = []
+ local.strong_store.locks_held.append(name)
+
+ try:
+ if external and not CONF.disable_process_locking:
+ LOG.debug(_('Attempting to grab file lock "%(lock)s"'),
+ {'lock': name})
+
+ # We need a copy of lock_path because it is non-local
+ local_lock_path = lock_path or CONF.lock_path
+ if not local_lock_path:
+ raise cfg.RequiredOptError('lock_path')
+
+ if not os.path.exists(local_lock_path):
+ fileutils.ensure_tree(local_lock_path)
+ LOG.info(_('Created lock path: %s'), local_lock_path)
+
+ def add_prefix(name, prefix):
+ if not prefix:
+ return name
+ sep = '' if prefix.endswith('-') else '-'
+ return '%s%s%s' % (prefix, sep, name)
+
+ # NOTE(mikal): the lock name cannot contain directory
+ # separators
+ lock_file_name = add_prefix(name.replace(os.sep, '_'),
+ lock_file_prefix)
+
+ lock_file_path = os.path.join(local_lock_path, lock_file_name)
+
+ try:
+ lock = InterProcessLock(lock_file_path)
+ with lock as lock:
+ LOG.debug(_('Got file lock "%(lock)s" at %(path)s'),
+ {'lock': name, 'path': lock_file_path})
+ yield lock
+ finally:
+ LOG.debug(_('Released file lock "%(lock)s" at %(path)s'),
+ {'lock': name, 'path': lock_file_path})
+ else:
+ yield sem
+
+ finally:
+ local.strong_store.locks_held.remove(name)
+
+
+def synchronized(name, lock_file_prefix=None, external=False, lock_path=None):
+ """Synchronization decorator.
+
+ Decorating a method like so::
+
+ @synchronized('mylock')
+ def foo(self, *args):
+ ...
+
+ ensures that only one thread will execute the foo method at a time.
+
+ Different methods can share the same lock::
+
+ @synchronized('mylock')
+ def foo(self, *args):
+ ...
+
+ @synchronized('mylock')
+ def bar(self, *args):
+ ...
+
+ This way only one of either foo or bar can be executing at a time.
+ """
+
+ def wrap(f):
+ @functools.wraps(f)
+ def inner(*args, **kwargs):
+ try:
+ with lock(name, lock_file_prefix, external, lock_path):
+ LOG.debug(_('Got semaphore / lock "%(function)s"'),
+ {'function': f.__name__})
+ return f(*args, **kwargs)
+ finally:
+ LOG.debug(_('Semaphore / lock released "%(function)s"'),
+ {'function': f.__name__})
+ return inner
+ return wrap
+
+
+def synchronized_with_prefix(lock_file_prefix):
+ """Partial object generator for the synchronization decorator.
+
+ Redefine @synchronized in each project like so::
+
+ (in nova/utils.py)
+ from nova.openstack.common import lockutils
+
+ synchronized = lockutils.synchronized_with_prefix('nova-')
+
+
+ (in nova/foo.py)
+ from nova import utils
+
+ @utils.synchronized('mylock')
+ def bar(self, *args):
+ ...
+
+ The lock_file_prefix argument is used to provide lock files on disk with a
+ meaningful prefix.
+ """
+
+ return functools.partial(synchronized, lock_file_prefix=lock_file_prefix)
+
+
+def main(argv):
+ """Create a dir for locks and pass it to command from arguments
+
+ If you run this:
+ python -m openstack.common.lockutils python setup.py testr <etc>
+
+ a temporary directory will be created for all your locks and passed to all
+ your tests in an environment variable. The temporary dir will be deleted
+ afterwards and the return value will be preserved.
+ """
+
+ lock_dir = tempfile.mkdtemp()
+ os.environ["DESIGNATE_LOCK_PATH"] = lock_dir
+ try:
+ ret_val = subprocess.call(argv[1:])
+ finally:
+ shutil.rmtree(lock_dir, ignore_errors=True)
+ return ret_val
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))
diff --git a/designate/openstack/common/test.py b/designate/openstack/common/test.py
new file mode 100644
index 00000000..09d9210a
--- /dev/null
+++ b/designate/openstack/common/test.py
@@ -0,0 +1,53 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
+# 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.
+
+"""Common utilities used in testing"""
+
+import os
+
+import fixtures
+import testtools
+
+_TRUE_VALUES = ('True', 'true', '1', 'yes')
+
+
+class BaseTestCase(testtools.TestCase):
+ def setUp(self):
+ super(BaseTestCase, self).setUp()
+ self._set_timeout()
+ self._fake_output()
+ self.useFixture(fixtures.FakeLogger('designate.openstack.common'))
+ self.useFixture(fixtures.NestedTempfile())
+ self.useFixture(fixtures.TempHomeDir())
+
+ def _set_timeout(self):
+ test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
+ try:
+ test_timeout = int(test_timeout)
+ except ValueError:
+ # If timeout value is invalid do not set a timeout.
+ test_timeout = 0
+ if test_timeout > 0:
+ self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
+
+ def _fake_output(self):
+ if os.environ.get('OS_STDOUT_CAPTURE') in _TRUE_VALUES:
+ stdout = self.useFixture(fixtures.StringStream('stdout')).stream
+ self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
+ if os.environ.get('OS_STDERR_CAPTURE') in _TRUE_VALUES:
+ stderr = self.useFixture(fixtures.StringStream('stderr')).stream
+ self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
diff --git a/designate/tests/__init__.py b/designate/tests/__init__.py
index f55082fc..ac9d146d 100644
--- a/designate/tests/__init__.py
+++ b/designate/tests/__init__.py
@@ -14,14 +14,16 @@
# License for the specific language governing permissions and limitations
# under the License.
import copy
-import unittest2
-import mox
-import nose
+import fixtures
+import functools
import os
+from testtools import testcase
from oslo.config import cfg
from designate.openstack.common import log as logging
from designate.openstack.common.notifier import test_notifier
+from designate.openstack.common.fixture import config
from designate.openstack.common import policy
+from designate.openstack.common import test
from designate.context import DesignateContext
from designate import storage
from designate import exceptions
@@ -42,7 +44,18 @@ cfg.CONF.import_opt('database_connection', 'designate.storage.impl_sqlalchemy',
group='storage:sqlalchemy')
-class TestCase(unittest2.TestCase):
+class NotifierFixture(fixtures.Fixture):
+ def tearDown(self):
+ self.clear()
+
+ def get(self):
+ return test_notifier.NOTIFICATIONS
+
+ def clear(self):
+ test_notifier.NOTIFICATIONS = []
+
+
+class TestCase(test.BaseTestCase):
quota_fixtures = [{
'tenant_id': '12345',
'resource': 'domains',
@@ -90,7 +103,7 @@ class TestCase(unittest2.TestCase):
def setUp(self):
super(TestCase, self).setUp()
- self.mox = mox.Mox()
+ self.CONF = self.useFixture(config.Config(cfg.CONF)).conf
self.config(
notification_driver=[
@@ -120,6 +133,11 @@ class TestCase(unittest2.TestCase):
group='storage:sqlalchemy'
)
+ self.CONF([], project='designate')
+
+ self.notifications = NotifierFixture()
+ self.useFixture(self.notifications)
+
storage.setup_schema()
self.admin_context = self.get_admin_context()
@@ -128,13 +146,8 @@ class TestCase(unittest2.TestCase):
self.reset_notifications()
policy.reset()
storage.teardown_schema()
- cfg.CONF.reset()
- self.mox.UnsetStubs()
super(TestCase, self).tearDown()
- def skip(self, message=None):
- raise nose.SkipTest(message)
-
# Config Methods
def config(self, **kwargs):
group = kwargs.pop('group', None)
@@ -156,10 +169,10 @@ class TestCase(unittest2.TestCase):
# Other Utility Methods
def get_notifications(self):
- return test_notifier.NOTIFICATIONS
+ return self.notifications.get()
def reset_notifications(self):
- test_notifier.NOTIFICATIONS = []
+ self.notifications.clear()
# Service Methods
def get_agent_service(self):
@@ -264,3 +277,27 @@ class TestCase(unittest2.TestCase):
values=kwargs)
return self.central_service.create_record(context, domain['id'],
values=values)
+
+
+def _skip_decorator(func):
+ @functools.wraps(func)
+ def skip_if_not_implemented(*args, **kwargs):
+ try:
+ return func(*args, **kwargs)
+ except NotImplementedError as e:
+ raise testcase.TestSkipped(str(e))
+ except Exception as e:
+ if 'not implemented' in str(e):
+ raise testcase.TestSkipped(str(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)
diff --git a/designate/tests/test_agent/__init__.py b/designate/tests/test_agent/__init__.py
index 705debf1..5d34fe13 100644
--- a/designate/tests/test_agent/__init__.py
+++ b/designate/tests/test_agent/__init__.py
@@ -17,4 +17,4 @@ from designate.tests import TestCase
class AgentTestCase(TestCase):
- __test__ = False
+ pass
diff --git a/designate/tests/test_agent/test_service.py b/designate/tests/test_agent/test_service.py
index 1a19b8ba..e4fb3290 100644
--- a/designate/tests/test_agent/test_service.py
+++ b/designate/tests/test_agent/test_service.py
@@ -17,8 +17,6 @@ from designate.tests.test_agent import AgentTestCase
class AgentServiceTest(AgentTestCase):
- __test__ = True
-
def setUp(self):
super(AgentServiceTest, self).setUp()
self.service = self.get_agent_service()
diff --git a/designate/tests/test_api/__init__.py b/designate/tests/test_api/__init__.py
index e1467a77..bf9cc4d7 100644
--- a/designate/tests/test_api/__init__.py
+++ b/designate/tests/test_api/__init__.py
@@ -17,4 +17,4 @@ from designate.tests import TestCase
class ApiTestCase(TestCase):
- __test__ = False
+ pass
diff --git a/designate/tests/test_api/test_middleware.py b/designate/tests/test_api/test_middleware.py
index b860c57b..af59274b 100644
--- a/designate/tests/test_api/test_middleware.py
+++ b/designate/tests/test_api/test_middleware.py
@@ -33,8 +33,6 @@ class FakeRequest(object):
class MaintenanceMiddlewareTest(ApiTestCase):
- __test__ = True
-
def test_process_request_disabled(self):
self.config(maintenance_mode=False, group='service:api')
@@ -107,8 +105,6 @@ class MaintenanceMiddlewareTest(ApiTestCase):
class KeystoneContextMiddlewareTest(ApiTestCase):
- __test__ = True
-
def test_process_request(self):
app = middleware.KeystoneContextMiddleware({})
@@ -168,8 +164,6 @@ class KeystoneContextMiddlewareTest(ApiTestCase):
class NoAuthContextMiddlewareTest(ApiTestCase):
- __test__ = True
-
def test_process_request(self):
app = middleware.NoAuthContextMiddleware({})
diff --git a/designate/tests/test_api/test_service.py b/designate/tests/test_api/test_service.py
index 6e2ceb5d..538eb33b 100644
--- a/designate/tests/test_api/test_service.py
+++ b/designate/tests/test_api/test_service.py
@@ -17,8 +17,6 @@ from designate.tests.test_api import ApiTestCase
class ApiServiceTest(ApiTestCase):
- __test__ = True
-
def setUp(self):
super(ApiServiceTest, self).setUp()
diff --git a/designate/tests/test_api/test_v1/__init__.py b/designate/tests/test_api/test_v1/__init__.py
index b6ca653e..bc31209a 100644
--- a/designate/tests/test_api/test_v1/__init__.py
+++ b/designate/tests/test_api/test_v1/__init__.py
@@ -24,8 +24,6 @@ LOG = logging.getLogger(__name__)
class ApiV1Test(ApiTestCase):
- __test__ = False
-
def setUp(self):
super(ApiV1Test, self).setUp()
diff --git a/designate/tests/test_api/test_v1/test_domains.py b/designate/tests/test_api/test_v1/test_domains.py
index 3acbbd5d..2a2dcdf6 100644
--- a/designate/tests/test_api/test_v1/test_domains.py
+++ b/designate/tests/test_api/test_v1/test_domains.py
@@ -26,8 +26,6 @@ LOG = logging.getLogger(__name__)
class ApiV1DomainsTest(ApiV1Test):
- __test__ = True
-
def test_create_domain(self):
# Create a server
self.create_server()
diff --git a/designate/tests/test_api/test_v1/test_records.py b/designate/tests/test_api/test_v1/test_records.py
index 7e45332e..24058619 100644
--- a/designate/tests/test_api/test_v1/test_records.py
+++ b/designate/tests/test_api/test_v1/test_records.py
@@ -25,8 +25,6 @@ LOG = logging.getLogger(__name__)
class ApiV1RecordsTest(ApiV1Test):
- __test__ = True
-
def setUp(self):
super(ApiV1RecordsTest, self).setUp()
diff --git a/designate/tests/test_api/test_v1/test_servers.py b/designate/tests/test_api/test_v1/test_servers.py
index 8b3334c3..bbdfb673 100644
--- a/designate/tests/test_api/test_v1/test_servers.py
+++ b/designate/tests/test_api/test_v1/test_servers.py
@@ -25,8 +25,6 @@ LOG = logging.getLogger(__name__)
class ApiV1ServersTest(ApiV1Test):
- __test__ = True
-
def test_create_server(self):
# Create a server
fixture = self.get_server_fixture(0)
diff --git a/designate/tests/test_api/test_v2/__init__.py b/designate/tests/test_api/test_v2/__init__.py
index 6dbdd9e5..66463794 100644
--- a/designate/tests/test_api/test_v2/__init__.py
+++ b/designate/tests/test_api/test_v2/__init__.py
@@ -24,8 +24,6 @@ LOG = logging.getLogger(__name__)
class ApiV2TestCase(ApiTestCase):
- __test__ = False
-
def setUp(self):
super(ApiV2TestCase, self).setUp()
diff --git a/designate/tests/test_api/test_v2/test_limits.py b/designate/tests/test_api/test_v2/test_limits.py
index db68723c..69dbd5e8 100644
--- a/designate/tests/test_api/test_v2/test_limits.py
+++ b/designate/tests/test_api/test_v2/test_limits.py
@@ -18,8 +18,6 @@ from designate.tests.test_api.test_v2 import ApiV2TestCase
class ApiV2LimitsTest(ApiV2TestCase):
- __test__ = True
-
def test_get_limits(self):
response = self.client.get('/limits/')
diff --git a/designate/tests/test_api/test_v2/test_zones.py b/designate/tests/test_api/test_v2/test_zones.py
index 9bfde4b9..08b332bf 100644
--- a/designate/tests/test_api/test_v2/test_zones.py
+++ b/designate/tests/test_api/test_v2/test_zones.py
@@ -22,8 +22,6 @@ from designate.tests.test_api.test_v2 import ApiV2TestCase
class ApiV2ZonesTest(ApiV2TestCase):
- __test__ = True
-
def setUp(self):
super(ApiV2ZonesTest, self).setUp()
diff --git a/designate/tests/test_backend/__init__.py b/designate/tests/test_backend/__init__.py
index a8a97cf2..b0c306c5 100644
--- a/designate/tests/test_backend/__init__.py
+++ b/designate/tests/test_backend/__init__.py
@@ -22,8 +22,6 @@ LOG = logging.getLogger(__name__)
class BackendTestCase(TestCase):
- __test__ = False
-
def get_backend_driver(self):
central_service = self.get_central_service()
return backend.get_backend(cfg.CONF['service:agent'].backend_driver,
diff --git a/designate/tests/test_backend/test_bind9.py b/designate/tests/test_backend/test_bind9.py
index 8da31b9a..31f01d72 100644
--- a/designate/tests/test_backend/test_bind9.py
+++ b/designate/tests/test_backend/test_bind9.py
@@ -20,8 +20,6 @@ LOG = logging.getLogger(__name__)
class Bind9BackendDriverTestCase(BackendTestCase):
- __test__ = True
-
def setUp(self):
super(Bind9BackendDriverTestCase, self).setUp()
diff --git a/designate/tests/test_backend/test_dnsmasq.py b/designate/tests/test_backend/test_dnsmasq.py
index 786a21d1..bc5f012e 100644
--- a/designate/tests/test_backend/test_dnsmasq.py
+++ b/designate/tests/test_backend/test_dnsmasq.py
@@ -20,8 +20,6 @@ LOG = logging.getLogger(__name__)
class DnsmasqBackendDriverTestCase(BackendTestCase):
- __test__ = True
-
def setUp(self):
super(DnsmasqBackendDriverTestCase, self).setUp()
diff --git a/designate/tests/test_backend/test_fake.py b/designate/tests/test_backend/test_fake.py
index 63ad1a60..d4adc037 100644
--- a/designate/tests/test_backend/test_fake.py
+++ b/designate/tests/test_backend/test_fake.py
@@ -20,8 +20,6 @@ LOG = logging.getLogger(__name__)
class FakeBackendDriverTestCase(BackendTestCase):
- __test__ = True
-
def setUp(self):
super(FakeBackendDriverTestCase, self).setUp()
diff --git a/designate/tests/test_backend/test_mysqlbind9.py b/designate/tests/test_backend/test_mysqlbind9.py
index 9c254a27..6cf8519a 100644
--- a/designate/tests/test_backend/test_mysqlbind9.py
+++ b/designate/tests/test_backend/test_mysqlbind9.py
@@ -20,8 +20,6 @@ LOG = logging.getLogger(__name__)
class MySQLBind9BackendDriverTestCase(BackendTestCase):
- __test__ = True
-
def setUp(self):
super(MySQLBind9BackendDriverTestCase, self).setUp()
diff --git a/designate/tests/test_backend/test_powerdns.py b/designate/tests/test_backend/test_powerdns.py
index b34a13b5..dfe8fd77 100644
--- a/designate/tests/test_backend/test_powerdns.py
+++ b/designate/tests/test_backend/test_powerdns.py
@@ -20,8 +20,6 @@ LOG = logging.getLogger(__name__)
class PowerDNSBackendDriverTestCase(BackendTestCase):
- __test__ = True
-
def setUp(self):
super(PowerDNSBackendDriverTestCase, self).setUp()
diff --git a/designate/tests/test_central/__init__.py b/designate/tests/test_central/__init__.py
index c61c7e08..088df403 100644
--- a/designate/tests/test_central/__init__.py
+++ b/designate/tests/test_central/__init__.py
@@ -17,4 +17,4 @@ from designate.tests import TestCase
class CentralTestCase(TestCase):
- __test__ = False
+ pass
diff --git a/designate/tests/test_central/test_service.py b/designate/tests/test_central/test_service.py
index 34d84dee..a879df10 100644
--- a/designate/tests/test_central/test_service.py
+++ b/designate/tests/test_central/test_service.py
@@ -14,6 +14,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import random
+import testtools
from designate.openstack.common import log as logging
from designate import exceptions
from designate.tests.test_central import CentralTestCase
@@ -22,8 +23,6 @@ LOG = logging.getLogger(__name__)
class CentralServiceTest(CentralTestCase):
- __test__ = True
-
def setUp(self):
super(CentralServiceTest, self).setUp()
self.central_service = self.get_central_service()
@@ -42,10 +41,10 @@ class CentralServiceTest(CentralTestCase):
self.central_service._is_valid_domain_name(context, 'valid.org.')
- with self.assertRaises(exceptions.InvalidDomainName):
+ with testtools.ExpectedException(exceptions.InvalidDomainName):
self.central_service._is_valid_domain_name(context, 'example.org.')
- with self.assertRaises(exceptions.InvalidDomainName):
+ with testtools.ExpectedException(exceptions.InvalidDomainName):
self.central_service._is_valid_domain_name(context, 'example.tld.')
def test_is_valid_record_name(self):
@@ -61,15 +60,15 @@ class CentralServiceTest(CentralTestCase):
'valid.example.org.',
'A')
- with self.assertRaises(exceptions.InvalidRecordName):
+ with testtools.ExpectedException(exceptions.InvalidRecordName):
self.central_service._is_valid_record_name(
context, domain, 'toolong.example.org.', 'A')
- with self.assertRaises(exceptions.InvalidRecordLocation):
+ with testtools.ExpectedException(exceptions.InvalidRecordLocation):
self.central_service._is_valid_record_name(
context, domain, 'a.example.COM.', 'A')
- with self.assertRaises(exceptions.InvalidRecordLocation):
+ with testtools.ExpectedException(exceptions.InvalidRecordLocation):
self.central_service._is_valid_record_name(
context, domain, 'example.org.', 'CNAME')
@@ -201,12 +200,15 @@ class CentralServiceTest(CentralTestCase):
self.central_service.delete_server(context, server['id'])
# Fetch the server again, ensuring an exception is raised
- with self.assertRaises(exceptions.ServerNotFound):
- self.central_service.get_server(context, server['id'])
+ self.assertRaises(
+ exceptions.ServerNotFound,
+ self.central_service.get_server,
+ context, server['id'])
# Try to delete last remaining server - expect exception
- with self.assertRaises(exceptions.LastServerDeleteNotAllowed):
- self.central_service.delete_server(context, server2['id'])
+ self.assertRaises(
+ exceptions.LastServerDeleteNotAllowed,
+ self.central_service.delete_server, context, server2['id'])
# TsigKey Tests
def test_create_tsigkey(self):
@@ -288,7 +290,7 @@ class CentralServiceTest(CentralTestCase):
self.central_service.delete_tsigkey(context, tsigkey['id'])
# Fetch the tsigkey again, ensuring an exception is raised
- with self.assertRaises(exceptions.TsigKeyNotFound):
+ with testtools.ExpectedException(exceptions.TsigKeyNotFound):
self.central_service.get_tsigkey(context, tsigkey['id'])
# Tenant Tests
@@ -311,7 +313,7 @@ class CentralServiceTest(CentralTestCase):
# Set the policy to reject the authz
self.policy({'count_tenants': '!'})
- with self.assertRaises(exceptions.Forbidden):
+ with testtools.ExpectedException(exceptions.Forbidden):
self.central_service.count_tenants(self.get_context())
# Domain Tests
@@ -360,7 +362,7 @@ class CentralServiceTest(CentralTestCase):
self.create_domain()
- with self.assertRaises(exceptions.OverQuota):
+ with testtools.ExpectedException(exceptions.OverQuota):
self.create_domain()
def test_create_subdomain(self):
@@ -402,7 +404,7 @@ class CentralServiceTest(CentralTestCase):
values['name'] = 'www.%s' % parent_domain['name']
# Attempt to create the subdomain
- with self.assertRaises(exceptions.Forbidden):
+ with testtools.ExpectedException(exceptions.Forbidden):
self.central_service.create_domain(context, values=values)
def test_create_blacklisted_domain_success(self):
@@ -444,7 +446,7 @@ class CentralServiceTest(CentralTestCase):
email='info@blacklisted.com'
)
- with self.assertRaises(exceptions.InvalidDomainName):
+ with testtools.ExpectedException(exceptions.InvalidDomainName):
# Create a domain
self.central_service.create_domain(context, values=values)
@@ -470,7 +472,7 @@ class CentralServiceTest(CentralTestCase):
email='info@invalid.com'
)
- with self.assertRaises(exceptions.InvalidTLD):
+ with testtools.ExpectedException(exceptions.InvalidTLD):
# Create an invalid domain
self.central_service.create_domain(context, values=values)
@@ -561,7 +563,7 @@ class CentralServiceTest(CentralTestCase):
# Retrieve the servers list
servers = self.central_service.get_domain_servers(context,
domain['id'])
- self.assertGreater(len(servers), 0)
+ self.assertTrue(len(servers) > 0)
def test_find_domain(self):
context = self.get_admin_context()
@@ -597,7 +599,7 @@ class CentralServiceTest(CentralTestCase):
expected_domain['id'])
# Ensure the domain was updated correctly
- self.assertGreater(domain['serial'], expected_domain['serial'])
+ self.assertTrue(domain['serial'] > expected_domain['serial'])
self.assertEqual(domain['email'], 'new@example.com')
# Ensure we sent exactly 1 notification
@@ -644,7 +646,7 @@ class CentralServiceTest(CentralTestCase):
expected_domain = self.create_domain()
# Update the domain
- with self.assertRaises(exceptions.BadRequest):
+ with testtools.ExpectedException(exceptions.BadRequest):
values = dict(name='renamed-domain.com.')
self.central_service.update_domain(context, expected_domain['id'],
values=values)
@@ -662,7 +664,7 @@ class CentralServiceTest(CentralTestCase):
self.central_service.delete_domain(context, domain['id'])
# Fetch the domain again, ensuring an exception is raised
- with self.assertRaises(exceptions.DomainNotFound):
+ with testtools.ExpectedException(exceptions.DomainNotFound):
self.central_service.get_domain(context, domain['id'])
# Ensure we sent exactly 1 notification
@@ -696,7 +698,7 @@ class CentralServiceTest(CentralTestCase):
self.central_service.create_domain(context, values=values)
# Attempt to delete the parent domain
- with self.assertRaises(exceptions.DomainHasSubdomain):
+ with testtools.ExpectedException(exceptions.DomainHasSubdomain):
self.central_service.delete_domain(context, parent_domain['id'])
def test_count_domains(self):
@@ -717,7 +719,7 @@ class CentralServiceTest(CentralTestCase):
# Set the policy to reject the authz
self.policy({'count_domains': '!'})
- with self.assertRaises(exceptions.Forbidden):
+ with testtools.ExpectedException(exceptions.Forbidden):
self.central_service.count_domains(self.get_context())
def test_touch_domain(self):
@@ -734,7 +736,7 @@ class CentralServiceTest(CentralTestCase):
expected_domain['id'])
# Ensure the serial was incremented
- self.assertGreater(domain['serial'], expected_domain['serial'])
+ self.assertTrue(domain['serial'] > expected_domain['serial'])
# Record Tests
def test_create_record(self):
@@ -766,7 +768,7 @@ class CentralServiceTest(CentralTestCase):
self.create_record(domain)
- with self.assertRaises(exceptions.OverQuota):
+ with testtools.ExpectedException(exceptions.OverQuota):
self.create_record(domain)
def test_create_record_without_incrementing_serial(self):
@@ -806,7 +808,7 @@ class CentralServiceTest(CentralTestCase):
)
# Attempt to create a CNAME record at the apex
- with self.assertRaises(exceptions.InvalidRecordLocation):
+ with testtools.ExpectedException(exceptions.InvalidRecordLocation):
self.central_service.create_record(context, domain['id'],
values=values)
@@ -874,7 +876,7 @@ class CentralServiceTest(CentralTestCase):
values=values)
# Attempt to create a CNAME record alongside an A record
- with self.assertRaises(exceptions.InvalidRecordLocation):
+ with testtools.ExpectedException(exceptions.InvalidRecordLocation):
values = dict(
name='www.%s' % domain['name'],
type='CNAME',
@@ -898,7 +900,7 @@ class CentralServiceTest(CentralTestCase):
values=values)
# Attempt to create a CNAME record alongside an A record
- with self.assertRaises(exceptions.InvalidRecordLocation):
+ with testtools.ExpectedException(exceptions.InvalidRecordLocation):
values = dict(
name='www.%s' % domain['name'],
type='A',
@@ -922,7 +924,7 @@ class CentralServiceTest(CentralTestCase):
values=values)
# Attempt to create a second PTR with the same name.
- with self.assertRaises(exceptions.DuplicateRecord):
+ with testtools.ExpectedException(exceptions.DuplicateRecord):
values = dict(
name='1.%s' % domain['name'],
type='PTR',
@@ -998,7 +1000,7 @@ class CentralServiceTest(CentralTestCase):
expected_record = self.create_record(domain, name=record_name)
# Ensure we get a 404 if we use the incorrect domain_id
- with self.assertRaises(exceptions.RecordNotFound):
+ with testtools.ExpectedException(exceptions.RecordNotFound):
self.central_service.get_record(context, other_domain['id'],
expected_record['id'])
@@ -1063,7 +1065,7 @@ class CentralServiceTest(CentralTestCase):
values = dict(data='127.0.0.2')
# Ensure we get a 404 if we use the incorrect domain_id
- with self.assertRaises(exceptions.RecordNotFound):
+ with testtools.ExpectedException(exceptions.RecordNotFound):
self.central_service.update_record(context, other_domain['id'],
expected_record['id'],
values=values)
@@ -1091,7 +1093,7 @@ class CentralServiceTest(CentralTestCase):
values=values)
# Attempt to create a second PTR with the same name.
- with self.assertRaises(exceptions.DuplicateRecord):
+ with testtools.ExpectedException(exceptions.DuplicateRecord):
values = dict(
name='1.%s' % domain['name']
)
@@ -1156,7 +1158,7 @@ class CentralServiceTest(CentralTestCase):
self.central_service.delete_record(context, domain['id'], record['id'])
# Fetch the record again, ensuring an exception is raised
- with self.assertRaises(exceptions.RecordNotFound):
+ with testtools.ExpectedException(exceptions.RecordNotFound):
self.central_service.get_record(context, domain['id'],
record['id'])
@@ -1175,7 +1177,7 @@ class CentralServiceTest(CentralTestCase):
increment_serial=False)
# Fetch the record again, ensuring an exception is raised
- with self.assertRaises(exceptions.RecordNotFound):
+ with testtools.ExpectedException(exceptions.RecordNotFound):
self.central_service.get_record(context, domain['id'],
record['id'])
@@ -1192,7 +1194,7 @@ class CentralServiceTest(CentralTestCase):
record = self.create_record(domain)
# Ensure we get a 404 if we use the incorrect domain_id
- with self.assertRaises(exceptions.RecordNotFound):
+ with testtools.ExpectedException(exceptions.RecordNotFound):
self.central_service.delete_record(context, other_domain['id'],
record['id'])
@@ -1215,5 +1217,5 @@ class CentralServiceTest(CentralTestCase):
# Set the policy to reject the authz
self.policy({'count_records': '!'})
- with self.assertRaises(exceptions.Forbidden):
+ with testtools.ExpectedException(exceptions.Forbidden):
self.central_service.count_records(self.get_context())
diff --git a/designate/tests/test_notification_handler/__init__.py b/designate/tests/test_notification_handler/__init__.py
index 265be55f..ce897cd6 100644
--- a/designate/tests/test_notification_handler/__init__.py
+++ b/designate/tests/test_notification_handler/__init__.py
@@ -15,16 +15,19 @@
# under the License.
import json
import os
+import six
+import testtools
from designate.notification_handler.base import Handler
from designate.tests import TestCase
+from designate.tests import SkipNotImplementedMeta
FIXTURES_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__),
'..',
'sample_notifications'))
+@six.add_metaclass(SkipNotImplementedMeta)
class NotificationHandlerTestCase(TestCase):
- __test__ = False
__plugin_base__ = Handler
def setUp(self):
@@ -47,9 +50,11 @@ class NotificationHandlerTestCase(TestCase):
return json.load(fh)
def test_invalid_event_type(self):
+ if not hasattr(self, 'plugin'):
+ raise NotImplementedError
event_type = 'invalid'
self.assertNotIn(event_type, self.plugin.get_event_types())
- with self.assertRaises(ValueError):
+ with testtools.ExpectedException(ValueError):
self.plugin.process_notification(event_type, 'payload')
diff --git a/designate/tests/test_notification_handler/test_nova.py b/designate/tests/test_notification_handler/test_nova.py
index 1fd9690f..7863667c 100644
--- a/designate/tests/test_notification_handler/test_nova.py
+++ b/designate/tests/test_notification_handler/test_nova.py
@@ -22,8 +22,6 @@ LOG = logging.getLogger(__name__)
class NovaFixedHandlerTest(NotificationHandlerTestCase):
- __test__ = True
-
def setUp(self):
super(NovaFixedHandlerTest, self).setUp()
@@ -71,7 +69,7 @@ class NovaFixedHandlerTest(NotificationHandlerTestCase):
records = self.central_service.find_records(self.admin_context,
self.domain_id)
- self.assertGreaterEqual(len(records), 1)
+ self.assertTrue(len(records) >= 1)
self.plugin.process_notification(event_type, fixture['payload'])
diff --git a/designate/tests/test_notification_handler/test_quantum.py b/designate/tests/test_notification_handler/test_quantum.py
index f276ca18..66781ba7 100644
--- a/designate/tests/test_notification_handler/test_quantum.py
+++ b/designate/tests/test_notification_handler/test_quantum.py
@@ -22,8 +22,6 @@ LOG = logging.getLogger(__name__)
class QuantumFloatingHandlerTest(NotificationHandlerTestCase):
- __test__ = True
-
def setUp(self):
super(QuantumFloatingHandlerTest, self).setUp()
@@ -71,7 +69,7 @@ class QuantumFloatingHandlerTest(NotificationHandlerTestCase):
records = self.central_service.find_records(self.admin_context,
self.domain_id)
- self.assertGreaterEqual(len(records), 1)
+ self.assertTrue(len(records) >= 1)
self.plugin.process_notification(event_type, fixture['payload'])
diff --git a/designate/tests/test_quota/__init__.py b/designate/tests/test_quota/__init__.py
index 136abd3e..20f46f45 100644
--- a/designate/tests/test_quota/__init__.py
+++ b/designate/tests/test_quota/__init__.py
@@ -13,6 +13,7 @@
# 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 testtools
from oslo.config import cfg
from designate.openstack.common import log as logging
from designate.tests import TestCase
@@ -23,8 +24,6 @@ LOG = logging.getLogger(__name__)
class QuotaTestCase(TestCase):
- __test__ = False
-
def setUp(self):
super(QuotaTestCase, self).setUp()
self.quota = quota.get_quota()
@@ -43,10 +42,10 @@ class QuotaTestCase(TestCase):
def test_limit_check_unknown(self):
context = self.get_admin_context()
- with self.assertRaises(exceptions.QuotaResourceUnknown):
+ with testtools.ExpectedException(exceptions.QuotaResourceUnknown):
self.quota.limit_check(context, 'tenant_id', unknown=0)
- with self.assertRaises(exceptions.QuotaResourceUnknown):
+ with testtools.ExpectedException(exceptions.QuotaResourceUnknown):
self.quota.limit_check(context, 'tenant_id', unknown=0, domains=0)
def test_limit_check_under(self):
@@ -67,11 +66,11 @@ class QuotaTestCase(TestCase):
def test_limit_check_at(self):
context = self.get_admin_context()
- with self.assertRaises(exceptions.OverQuota):
+ with testtools.ExpectedException(exceptions.OverQuota):
self.quota.limit_check(context, 'tenant_id',
domains=cfg.CONF.quota_domains)
- with self.assertRaises(exceptions.OverQuota):
+ with testtools.ExpectedException(exceptions.OverQuota):
self.quota.limit_check(
context,
'tenant_id',
@@ -80,20 +79,20 @@ class QuotaTestCase(TestCase):
def test_limit_check_over(self):
context = self.get_admin_context()
- with self.assertRaises(exceptions.OverQuota):
+ with testtools.ExpectedException(exceptions.OverQuota):
self.quota.limit_check(context, 'tenant_id', domains=99999)
- with self.assertRaises(exceptions.OverQuota):
+ with testtools.ExpectedException(exceptions.OverQuota):
self.quota.limit_check(context, 'tenant_id', domain_records=99999)
- with self.assertRaises(exceptions.OverQuota):
+ with testtools.ExpectedException(exceptions.OverQuota):
self.quota.limit_check(context, 'tenant_id', domains=99999,
domain_records=99999)
- with self.assertRaises(exceptions.OverQuota):
+ with testtools.ExpectedException(exceptions.OverQuota):
self.quota.limit_check(context, 'tenant_id', domains=99999,
domain_records=0)
- with self.assertRaises(exceptions.OverQuota):
+ with testtools.ExpectedException(exceptions.OverQuota):
self.quota.limit_check(context, 'tenant_id', domains=0,
domain_records=99999)
diff --git a/designate/tests/test_quota/test_noop.py b/designate/tests/test_quota/test_noop.py
index 6923c6b6..9a160d7d 100644
--- a/designate/tests/test_quota/test_noop.py
+++ b/designate/tests/test_quota/test_noop.py
@@ -20,8 +20,6 @@ LOG = logging.getLogger(__name__)
class NoopQuotaTest(QuotaTestCase):
- __test__ = True
-
def setUp(self):
self.config(quota_driver='noop')
super(NoopQuotaTest, self).setUp()
diff --git a/designate/tests/test_quota/test_storage.py b/designate/tests/test_quota/test_storage.py
index 6ae904b3..95a233f4 100644
--- a/designate/tests/test_quota/test_storage.py
+++ b/designate/tests/test_quota/test_storage.py
@@ -20,8 +20,6 @@ LOG = logging.getLogger(__name__)
class StorageQuotaTest(QuotaTestCase):
- __test__ = True
-
def setUp(self):
self.config(quota_driver='storage')
super(StorageQuotaTest, self).setUp()
@@ -30,7 +28,7 @@ class StorageQuotaTest(QuotaTestCase):
quota = self.quota.set_quota(self.admin_context, 'tenant_id',
'domains', 1500)
- self.assertEquals(quota, {'domains': 1500})
+ self.assertEqual(quota, {'domains': 1500})
# Drop into the storage layer directly to ensure the quota was created
# sucessfully.
@@ -42,9 +40,9 @@ class StorageQuotaTest(QuotaTestCase):
quota = self.quota.storage_api.find_quota(self.admin_context,
criterion)
- self.assertEquals(quota['tenant_id'], 'tenant_id')
- self.assertEquals(quota['resource'], 'domains')
- self.assertEquals(quota['hard_limit'], 1500)
+ self.assertEqual(quota['tenant_id'], 'tenant_id')
+ self.assertEqual(quota['resource'], 'domains')
+ self.assertEqual(quota['hard_limit'], 1500)
def test_set_quota_update(self):
# First up, Create the quota
@@ -63,9 +61,9 @@ class StorageQuotaTest(QuotaTestCase):
quota = self.quota.storage_api.find_quota(self.admin_context,
criterion)
- self.assertEquals(quota['tenant_id'], 'tenant_id')
- self.assertEquals(quota['resource'], 'domains')
- self.assertEquals(quota['hard_limit'], 1234)
+ self.assertEqual(quota['tenant_id'], 'tenant_id')
+ self.assertEqual(quota['resource'], 'domains')
+ self.assertEqual(quota['hard_limit'], 1234)
def test_reset_quotas(self):
# First up, Create a domains quota
@@ -87,4 +85,4 @@ class StorageQuotaTest(QuotaTestCase):
quotas = self.quota.storage_api.find_quotas(self.admin_context,
criterion)
- self.assertEquals(0, len(quotas))
+ self.assertEqual(0, len(quotas))
diff --git a/designate/tests/test_resources/test_schemas/test_v2.py b/designate/tests/test_resources/test_schemas/test_v2.py
index b5a8df83..fad6c1d0 100644
--- a/designate/tests/test_resources/test_schemas/test_v2.py
+++ b/designate/tests/test_resources/test_schemas/test_v2.py
@@ -13,6 +13,7 @@
# 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 testtools
from designate.openstack.common import log as logging
from designate import exceptions
from designate import schema
@@ -22,8 +23,6 @@ LOG = logging.getLogger(__name__)
class SchemasV2Test(TestCase):
- __test__ = True
-
def test_recordset(self):
validator = schema.Schema('v2', 'recordset')
@@ -54,7 +53,7 @@ class SchemasV2Test(TestCase):
}
})
- with self.assertRaises(exceptions.InvalidObject):
+ with testtools.ExpectedException(exceptions.InvalidObject):
# Fail Expected - Empty Records Array
validator.validate({
'recordset': {
@@ -66,7 +65,7 @@ class SchemasV2Test(TestCase):
}
})
- with self.assertRaises(exceptions.InvalidObject):
+ with testtools.ExpectedException(exceptions.InvalidObject):
# Fail Expected - No Records
validator.validate({
'recordset': {
@@ -77,7 +76,7 @@ class SchemasV2Test(TestCase):
}
})
- with self.assertRaises(exceptions.InvalidObject):
+ with testtools.ExpectedException(exceptions.InvalidObject):
# Fail Expected - MX records in an A RRset
validator.validate({
'recordset': {
@@ -92,7 +91,7 @@ class SchemasV2Test(TestCase):
}
})
- with self.assertRaises(exceptions.InvalidObject):
+ with testtools.ExpectedException(exceptions.InvalidObject):
# Fail Expected - A records in an MX RRset
validator.validate({
'recordset': {
@@ -107,7 +106,7 @@ class SchemasV2Test(TestCase):
}
})
- with self.assertRaises(exceptions.InvalidObject):
+ with testtools.ExpectedException(exceptions.InvalidObject):
# Fail Expected - AAAA records in an A RRset
validator.validate({
'recordset': {
diff --git a/designate/tests/test_storage/__init__.py b/designate/tests/test_storage/__init__.py
index f99388a4..06e1098b 100644
--- a/designate/tests/test_storage/__init__.py
+++ b/designate/tests/test_storage/__init__.py
@@ -13,21 +13,15 @@
# 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 testtools
+
from designate.openstack.common import log as logging
-from designate.tests import TestCase
-from designate import storage
from designate import exceptions
LOG = logging.getLogger(__name__)
-class StorageTestCase(TestCase):
- __test__ = False
-
- def setUp(self):
- super(StorageTestCase, self).setUp()
- self.storage = storage.get_storage()
-
+class StorageTestCase(object):
def create_quota(self, fixture=0, values={}):
fixture = self.get_quota_fixture(fixture, values)
return fixture, self.storage.create_quota(self.admin_context, fixture)
@@ -70,7 +64,7 @@ class StorageTestCase(TestCase):
# Create the initial quota
self.create_quota()
- with self.assertRaises(exceptions.DuplicateQuota):
+ with testtools.ExpectedException(exceptions.DuplicateQuota):
self.create_quota()
def test_find_quotas(self):
@@ -137,7 +131,7 @@ class StorageTestCase(TestCase):
self.assertEqual(actual['hard_limit'], expected['hard_limit'])
def test_get_quota_missing(self):
- with self.assertRaises(exceptions.QuotaNotFound):
+ with testtools.ExpectedException(exceptions.QuotaNotFound):
uuid = 'caf771fc-6b05-4891-bee1-c2a48621f57b'
self.storage.get_quota(self.admin_context, uuid)
@@ -174,7 +168,7 @@ class StorageTestCase(TestCase):
tenant_id=expected['tenant_id'] + "NOT FOUND"
)
- with self.assertRaises(exceptions.QuotaNotFound):
+ with testtools.ExpectedException(exceptions.QuotaNotFound):
self.storage.find_quota(self.admin_context, criterion)
def test_update_quota(self):
@@ -195,12 +189,12 @@ class StorageTestCase(TestCase):
values = self.quota_fixtures[0]
- with self.assertRaises(exceptions.DuplicateQuota):
+ with testtools.ExpectedException(exceptions.DuplicateQuota):
self.storage.update_quota(self.admin_context, quota['id'],
values)
def test_update_quota_missing(self):
- with self.assertRaises(exceptions.QuotaNotFound):
+ with testtools.ExpectedException(exceptions.QuotaNotFound):
uuid = 'caf771fc-6b05-4891-bee1-c2a48621f57b'
self.storage.update_quota(self.admin_context, uuid, {})
@@ -209,11 +203,11 @@ class StorageTestCase(TestCase):
self.storage.delete_quota(self.admin_context, quota['id'])
- with self.assertRaises(exceptions.QuotaNotFound):
+ with testtools.ExpectedException(exceptions.QuotaNotFound):
self.storage.get_quota(self.admin_context, quota['id'])
def test_delete_quota_missing(self):
- with self.assertRaises(exceptions.QuotaNotFound):
+ with testtools.ExpectedException(exceptions.QuotaNotFound):
uuid = 'caf771fc-6b05-4891-bee1-c2a48621f57b'
self.storage.delete_quota(self.admin_context, uuid)
@@ -235,7 +229,7 @@ class StorageTestCase(TestCase):
# Create the Initial Server
self.create_server()
- with self.assertRaises(exceptions.DuplicateServer):
+ with testtools.ExpectedException(exceptions.DuplicateServer):
self.create_server()
def test_find_servers(self):
@@ -290,7 +284,7 @@ class StorageTestCase(TestCase):
self.assertEqual(str(actual['name']), str(expected['name']))
def test_get_server_missing(self):
- with self.assertRaises(exceptions.ServerNotFound):
+ with testtools.ExpectedException(exceptions.ServerNotFound):
uuid = 'caf771fc-6b05-4891-bee1-c2a48621f57b'
self.storage.get_server(self.admin_context, uuid)
@@ -310,12 +304,12 @@ class StorageTestCase(TestCase):
values = self.server_fixtures[0]
- with self.assertRaises(exceptions.DuplicateServer):
+ with testtools.ExpectedException(exceptions.DuplicateServer):
self.storage.update_server(self.admin_context, server['id'],
values)
def test_update_server_missing(self):
- with self.assertRaises(exceptions.ServerNotFound):
+ with testtools.ExpectedException(exceptions.ServerNotFound):
uuid = 'caf771fc-6b05-4891-bee1-c2a48621f57b'
self.storage.update_server(self.admin_context, uuid, {})
@@ -324,11 +318,11 @@ class StorageTestCase(TestCase):
self.storage.delete_server(self.admin_context, server['id'])
- with self.assertRaises(exceptions.ServerNotFound):
+ with testtools.ExpectedException(exceptions.ServerNotFound):
self.storage.get_server(self.admin_context, server['id'])
def test_delete_server_missing(self):
- with self.assertRaises(exceptions.ServerNotFound):
+ with testtools.ExpectedException(exceptions.ServerNotFound):
uuid = 'caf771fc-6b05-4891-bee1-c2a48621f57b'
self.storage.delete_server(self.admin_context, uuid)
@@ -353,7 +347,7 @@ class StorageTestCase(TestCase):
values = self.get_tsigkey_fixture(1)
values['name'] = tsigkey_one['name']
- with self.assertRaises(exceptions.DuplicateTsigKey):
+ with testtools.ExpectedException(exceptions.DuplicateTsigKey):
self.create_tsigkey(values=values)
def test_find_tsigkeys(self):
@@ -415,7 +409,7 @@ class StorageTestCase(TestCase):
self.assertEqual(actual['secret'], expected['secret'])
def test_get_tsigkey_missing(self):
- with self.assertRaises(exceptions.TsigKeyNotFound):
+ with testtools.ExpectedException(exceptions.TsigKeyNotFound):
uuid = 'caf771fc-6b05-4891-bee1-c2a48621f57b'
self.storage.get_tsigkey(self.admin_context, uuid)
@@ -438,12 +432,12 @@ class StorageTestCase(TestCase):
values = self.tsigkey_fixtures[0]
- with self.assertRaises(exceptions.DuplicateTsigKey):
+ with testtools.ExpectedException(exceptions.DuplicateTsigKey):
self.storage.update_tsigkey(self.admin_context, tsigkey['id'],
values)
def test_update_tsigkey_missing(self):
- with self.assertRaises(exceptions.TsigKeyNotFound):
+ with testtools.ExpectedException(exceptions.TsigKeyNotFound):
uuid = 'caf771fc-6b05-4891-bee1-c2a48621f57b'
self.storage.update_tsigkey(self.admin_context, uuid, {})
@@ -452,11 +446,11 @@ class StorageTestCase(TestCase):
self.storage.delete_tsigkey(self.admin_context, tsigkey['id'])
- with self.assertRaises(exceptions.TsigKeyNotFound):
+ with testtools.ExpectedException(exceptions.TsigKeyNotFound):
self.storage.get_tsigkey(self.admin_context, tsigkey['id'])
def test_delete_tsigkey_missing(self):
- with self.assertRaises(exceptions.TsigKeyNotFound):
+ with testtools.ExpectedException(exceptions.TsigKeyNotFound):
uuid = 'caf771fc-6b05-4891-bee1-c2a48621f57b'
self.storage.delete_tsigkey(self.admin_context, uuid)
@@ -481,7 +475,7 @@ class StorageTestCase(TestCase):
'domain_count': 1
}]
- self.assertEquals(result, expected)
+ self.assertEqual(result, expected)
def test_get_tenant(self):
# create 2 domains in a tenant
@@ -494,10 +488,10 @@ class StorageTestCase(TestCase):
result = self.storage.get_tenant(self.admin_context, 1)
- self.assertEquals(result['id'], 1)
- self.assertEquals(result['domain_count'], 2)
- self.assertItemsEqual(result['domains'],
- [domain_1['name'], domain_2['name']])
+ self.assertEqual(result['id'], 1)
+ self.assertEqual(result['domain_count'], 2)
+ self.assertEqual(sorted(result['domains']),
+ [domain_1['name'], domain_2['name']])
def test_count_tenants(self):
# in the beginning, there should be nothing
@@ -536,7 +530,7 @@ class StorageTestCase(TestCase):
# Create the Initial Domain
self.create_domain()
- with self.assertRaises(exceptions.DuplicateDomain):
+ with testtools.ExpectedException(exceptions.DuplicateDomain):
self.create_domain()
def test_find_domains(self):
@@ -596,7 +590,7 @@ class StorageTestCase(TestCase):
self.assertIn('status', actual)
def test_get_domain_missing(self):
- with self.assertRaises(exceptions.DomainNotFound):
+ with testtools.ExpectedException(exceptions.DomainNotFound):
uuid = 'caf771fc-6b05-4891-bee1-c2a48621f57b'
self.storage.get_domain(self.admin_context, uuid)
@@ -641,7 +635,7 @@ class StorageTestCase(TestCase):
name=expected['name'] + "NOT FOUND"
)
- with self.assertRaises(exceptions.DomainNotFound):
+ with testtools.ExpectedException(exceptions.DomainNotFound):
self.storage.find_domain(self.admin_context, criterion)
def test_update_domain(self):
@@ -660,12 +654,12 @@ class StorageTestCase(TestCase):
fixture_one, domain_one = self.create_domain(fixture=0)
_, domain_two = self.create_domain(fixture=1)
- with self.assertRaises(exceptions.DuplicateDomain):
+ with testtools.ExpectedException(exceptions.DuplicateDomain):
self.storage.update_domain(self.admin_context, domain_two['id'],
fixture_one)
def test_update_domain_missing(self):
- with self.assertRaises(exceptions.DomainNotFound):
+ with testtools.ExpectedException(exceptions.DomainNotFound):
uuid = 'caf771fc-6b05-4891-bee1-c2a48621f57b'
self.storage.update_domain(self.admin_context, uuid, {})
@@ -674,11 +668,11 @@ class StorageTestCase(TestCase):
self.storage.delete_domain(self.admin_context, domain['id'])
- with self.assertRaises(exceptions.DomainNotFound):
+ with testtools.ExpectedException(exceptions.DomainNotFound):
self.storage.get_domain(self.admin_context, domain['id'])
def test_delete_domain_missing(self):
- with self.assertRaises(exceptions.DomainNotFound):
+ with testtools.ExpectedException(exceptions.DomainNotFound):
uuid = 'caf771fc-6b05-4891-bee1-c2a48621f57b'
self.storage.delete_domain(self.admin_context, uuid)
@@ -724,7 +718,7 @@ class StorageTestCase(TestCase):
# Create the First Record
self.create_record(domain)
- with self.assertRaises(exceptions.DuplicateRecord):
+ with testtools.ExpectedException(exceptions.DuplicateRecord):
# Attempt to create the second/duplicate record
self.create_record(domain)
@@ -807,7 +801,7 @@ class StorageTestCase(TestCase):
self.assertIn('status', actual)
def test_get_record_missing(self):
- with self.assertRaises(exceptions.RecordNotFound):
+ with testtools.ExpectedException(exceptions.RecordNotFound):
uuid = 'caf771fc-6b05-4891-bee1-c2a48621f57b'
self.storage.get_record(self.admin_context, uuid)
@@ -835,7 +829,7 @@ class StorageTestCase(TestCase):
name=expected['name'] + "NOT FOUND"
)
- with self.assertRaises(exceptions.RecordNotFound):
+ with testtools.ExpectedException(exceptions.RecordNotFound):
self.storage.find_record(self.admin_context, domain['id'],
criterion)
@@ -867,13 +861,13 @@ class StorageTestCase(TestCase):
record_one_fixture, _ = self.create_record(domain, fixture=0)
_, record_two = self.create_record(domain, fixture=1)
- with self.assertRaises(exceptions.DuplicateRecord):
+ with testtools.ExpectedException(exceptions.DuplicateRecord):
# Attempt to update the second record, making it a duplicate record
self.storage.update_record(self.admin_context, record_two['id'],
record_one_fixture)
def test_update_record_missing(self):
- with self.assertRaises(exceptions.RecordNotFound):
+ with testtools.ExpectedException(exceptions.RecordNotFound):
uuid = 'caf771fc-6b05-4891-bee1-c2a48621f57b'
self.storage.update_record(self.admin_context, uuid, {})
@@ -885,11 +879,11 @@ class StorageTestCase(TestCase):
self.storage.delete_record(self.admin_context, record['id'])
- with self.assertRaises(exceptions.RecordNotFound):
+ with testtools.ExpectedException(exceptions.RecordNotFound):
self.storage.get_record(self.admin_context, record['id'])
def test_delete_record_missing(self):
- with self.assertRaises(exceptions.RecordNotFound):
+ with testtools.ExpectedException(exceptions.RecordNotFound):
uuid = 'caf771fc-6b05-4891-bee1-c2a48621f57b'
self.storage.delete_record(self.admin_context, uuid)
diff --git a/designate/tests/test_storage/test_api.py b/designate/tests/test_storage/test_api.py
index 0569e26d..41623263 100644
--- a/designate/tests/test_storage/test_api.py
+++ b/designate/tests/test_storage/test_api.py
@@ -14,6 +14,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import mock
+import testtools
from designate.openstack.common import log as logging
from designate.tests import TestCase
from designate.storage import api as storage_api
@@ -26,8 +27,6 @@ class SentinelException(Exception):
class StorageAPITest(TestCase):
- __test__ = True
-
def setUp(self):
super(StorageAPITest, self).setUp()
self.storage_api = storage_api.StorageAPI()
@@ -69,7 +68,7 @@ class StorageAPITest(TestCase):
self._set_side_effect('create_quota', [{'id': 12345}])
- with self.assertRaises(SentinelException):
+ with testtools.ExpectedException(SentinelException):
with self.storage_api.create_quota(context, values):
raise SentinelException('Something Went Wrong')
@@ -85,7 +84,7 @@ class StorageAPITest(TestCase):
result = self.storage_api.get_quota(context, quota_id)
self._assert_called_with('get_quota', context, quota_id)
- self.assertEquals(quota, result)
+ self.assertEqual(quota, result)
def test_find_quotas(self):
context = mock.sentinel.context
@@ -96,7 +95,7 @@ class StorageAPITest(TestCase):
result = self.storage_api.find_quotas(context, criterion)
self._assert_called_with('find_quotas', context, criterion)
- self.assertEquals([quota], result)
+ self.assertEqual([quota], result)
def test_find_quota(self):
context = mock.sentinel.context
@@ -107,7 +106,7 @@ class StorageAPITest(TestCase):
result = self.storage_api.find_quota(context, criterion)
self._assert_called_with('find_quota', context, criterion)
- self.assertEquals(quota, result)
+ self.assertEqual(quota, result)
def test_update_quota(self):
context = mock.sentinel.context
@@ -124,7 +123,7 @@ class StorageAPITest(TestCase):
self._set_side_effect('get_quota', [{'id': 123, 'test': 1}])
- with self.assertRaises(SentinelException):
+ with testtools.ExpectedException(SentinelException):
with self.storage_api.update_quota(context, 123, values):
raise SentinelException('Something Went Wrong')
@@ -140,7 +139,7 @@ class StorageAPITest(TestCase):
self._set_side_effect('get_quota', [quota])
with self.storage_api.delete_quota(context, 123) as q:
- self.assertEquals(quota, q)
+ self.assertEqual(quota, q)
self._assert_called_with('delete_quota', context, 123)
@@ -150,7 +149,7 @@ class StorageAPITest(TestCase):
self._set_side_effect('get_quota', [quota])
- with self.assertRaises(SentinelException):
+ with testtools.ExpectedException(SentinelException):
with self.storage_api.delete_quota(context, 123):
raise SentinelException('Something Went Wrong')
@@ -175,7 +174,7 @@ class StorageAPITest(TestCase):
self._set_side_effect('create_server', [{'id': 12345}])
- with self.assertRaises(SentinelException):
+ with testtools.ExpectedException(SentinelException):
with self.storage_api.create_server(context, values):
raise SentinelException('Something Went Wrong')
@@ -191,7 +190,7 @@ class StorageAPITest(TestCase):
result = self.storage_api.get_server(context, server_id)
self._assert_called_with('get_server', context, server_id)
- self.assertEquals(server, result)
+ self.assertEqual(server, result)
def test_find_servers(self):
context = mock.sentinel.context
@@ -202,7 +201,7 @@ class StorageAPITest(TestCase):
result = self.storage_api.find_servers(context, criterion)
self._assert_called_with('find_servers', context, criterion)
- self.assertEquals([server], result)
+ self.assertEqual([server], result)
def test_find_server(self):
context = mock.sentinel.context
@@ -213,7 +212,7 @@ class StorageAPITest(TestCase):
result = self.storage_api.find_server(context, criterion)
self._assert_called_with('find_server', context, criterion)
- self.assertEquals(server, result)
+ self.assertEqual(server, result)
def test_update_server(self):
context = mock.sentinel.context
@@ -230,7 +229,7 @@ class StorageAPITest(TestCase):
self._set_side_effect('get_server', [{'id': 123, 'test': 1}])
- with self.assertRaises(SentinelException):
+ with testtools.ExpectedException(SentinelException):
with self.storage_api.update_server(context, 123, values):
raise SentinelException('Something Went Wrong')
@@ -246,7 +245,7 @@ class StorageAPITest(TestCase):
self._set_side_effect('get_server', [server])
with self.storage_api.delete_server(context, 123) as q:
- self.assertEquals(server, q)
+ self.assertEqual(server, q)
self._assert_called_with('delete_server', context, 123)
@@ -256,7 +255,7 @@ class StorageAPITest(TestCase):
self._set_side_effect('get_server', [server])
- with self.assertRaises(SentinelException):
+ with testtools.ExpectedException(SentinelException):
with self.storage_api.delete_server(context, 123):
raise SentinelException('Something Went Wrong')
@@ -281,7 +280,7 @@ class StorageAPITest(TestCase):
self._set_side_effect('create_tsigkey', [{'id': 12345}])
- with self.assertRaises(SentinelException):
+ with testtools.ExpectedException(SentinelException):
with self.storage_api.create_tsigkey(context, values):
raise SentinelException('Something Went Wrong')
@@ -297,7 +296,7 @@ class StorageAPITest(TestCase):
result = self.storage_api.get_tsigkey(context, tsigkey_id)
self._assert_called_with('get_tsigkey', context, tsigkey_id)
- self.assertEquals(tsigkey, result)
+ self.assertEqual(tsigkey, result)
def test_find_tsigkeys(self):
context = mock.sentinel.context
@@ -308,7 +307,7 @@ class StorageAPITest(TestCase):
result = self.storage_api.find_tsigkeys(context, criterion)
self._assert_called_with('find_tsigkeys', context, criterion)
- self.assertEquals([tsigkey], result)
+ self.assertEqual([tsigkey], result)
def test_find_tsigkey(self):
context = mock.sentinel.context
@@ -319,7 +318,7 @@ class StorageAPITest(TestCase):
result = self.storage_api.find_tsigkey(context, criterion)
self._assert_called_with('find_tsigkey', context, criterion)
- self.assertEquals(tsigkey, result)
+ self.assertEqual(tsigkey, result)
def test_update_tsigkey(self):
context = mock.sentinel.context
@@ -336,7 +335,7 @@ class StorageAPITest(TestCase):
self._set_side_effect('get_tsigkey', [{'id': 123, 'test': 1}])
- with self.assertRaises(SentinelException):
+ with testtools.ExpectedException(SentinelException):
with self.storage_api.update_tsigkey(context, 123, values):
raise SentinelException('Something Went Wrong')
@@ -352,7 +351,7 @@ class StorageAPITest(TestCase):
self._set_side_effect('get_tsigkey', [tsigkey])
with self.storage_api.delete_tsigkey(context, 123) as q:
- self.assertEquals(tsigkey, q)
+ self.assertEqual(tsigkey, q)
self._assert_called_with('delete_tsigkey', context, 123)
@@ -362,7 +361,7 @@ class StorageAPITest(TestCase):
self._set_side_effect('get_tsigkey', [tsigkey])
- with self.assertRaises(SentinelException):
+ with testtools.ExpectedException(SentinelException):
with self.storage_api.delete_tsigkey(context, 123):
raise SentinelException('Something Went Wrong')
@@ -377,7 +376,7 @@ class StorageAPITest(TestCase):
result = self.storage_api.find_tenants(context)
self._assert_called_with('find_tenants', context)
- self.assertEquals([tenant], result)
+ self.assertEqual([tenant], result)
def test_get_tenant(self):
context = mock.sentinel.context
@@ -387,7 +386,7 @@ class StorageAPITest(TestCase):
result = self.storage_api.get_tenant(context, 123)
self._assert_called_with('get_tenant', context, 123)
- self.assertEquals(tenant, result)
+ self.assertEqual(tenant, result)
def test_count_tenants(self):
context = mock.sentinel.context
@@ -396,7 +395,7 @@ class StorageAPITest(TestCase):
result = self.storage_api.count_tenants(context)
self._assert_called_with('count_tenants', context)
- self.assertEquals(1, result)
+ self.assertEqual(1, result)
# Domain Tests
def test_create_domain(self):
@@ -417,7 +416,7 @@ class StorageAPITest(TestCase):
self._set_side_effect('create_domain', [{'id': 12345}])
- with self.assertRaises(SentinelException):
+ with testtools.ExpectedException(SentinelException):
with self.storage_api.create_domain(context, values):
raise SentinelException('Something Went Wrong')
@@ -433,7 +432,7 @@ class StorageAPITest(TestCase):
result = self.storage_api.get_domain(context, domain_id)
self._assert_called_with('get_domain', context, domain_id)
- self.assertEquals(domain, result)
+ self.assertEqual(domain, result)
def test_find_domains(self):
context = mock.sentinel.context
@@ -444,7 +443,7 @@ class StorageAPITest(TestCase):
result = self.storage_api.find_domains(context, criterion)
self._assert_called_with('find_domains', context, criterion)
- self.assertEquals([domain], result)
+ self.assertEqual([domain], result)
def test_find_domain(self):
context = mock.sentinel.context
@@ -455,7 +454,7 @@ class StorageAPITest(TestCase):
result = self.storage_api.find_domain(context, criterion)
self._assert_called_with('find_domain', context, criterion)
- self.assertEquals(domain, result)
+ self.assertEqual(domain, result)
def test_update_domain(self):
context = mock.sentinel.context
@@ -472,7 +471,7 @@ class StorageAPITest(TestCase):
self._set_side_effect('get_domain', [{'id': 123, 'test': 1}])
- with self.assertRaises(SentinelException):
+ with testtools.ExpectedException(SentinelException):
with self.storage_api.update_domain(context, 123, values):
raise SentinelException('Something Went Wrong')
@@ -488,7 +487,7 @@ class StorageAPITest(TestCase):
self._set_side_effect('get_domain', [domain])
with self.storage_api.delete_domain(context, 123) as q:
- self.assertEquals(domain, q)
+ self.assertEqual(domain, q)
self._assert_called_with('delete_domain', context, 123)
@@ -498,7 +497,7 @@ class StorageAPITest(TestCase):
self._set_side_effect('get_domain', [domain])
- with self.assertRaises(SentinelException):
+ with testtools.ExpectedException(SentinelException):
with self.storage_api.delete_domain(context, 123):
raise SentinelException('Something Went Wrong')
@@ -523,7 +522,7 @@ class StorageAPITest(TestCase):
self._set_side_effect('create_record', [{'id': 12345}])
- with self.assertRaises(SentinelException):
+ with testtools.ExpectedException(SentinelException):
with self.storage_api.create_record(context, 123, values):
raise SentinelException('Something Went Wrong')
@@ -539,7 +538,7 @@ class StorageAPITest(TestCase):
result = self.storage_api.get_record(context, record_id)
self._assert_called_with('get_record', context, record_id)
- self.assertEquals(record, result)
+ self.assertEqual(record, result)
def test_find_records(self):
context = mock.sentinel.context
@@ -551,7 +550,7 @@ class StorageAPITest(TestCase):
result = self.storage_api.find_records(context, domain_id, criterion)
self._assert_called_with('find_records', context, domain_id, criterion)
- self.assertEquals([record], result)
+ self.assertEqual([record], result)
def test_find_record(self):
context = mock.sentinel.context
@@ -563,7 +562,7 @@ class StorageAPITest(TestCase):
result = self.storage_api.find_record(context, domain_id, criterion)
self._assert_called_with('find_record', context, domain_id, criterion)
- self.assertEquals(record, result)
+ self.assertEqual(record, result)
def test_update_record(self):
context = mock.sentinel.context
@@ -580,7 +579,7 @@ class StorageAPITest(TestCase):
self._set_side_effect('get_record', [{'id': 123, 'test': 1}])
- with self.assertRaises(SentinelException):
+ with testtools.ExpectedException(SentinelException):
with self.storage_api.update_record(context, 123, values):
raise SentinelException('Something Went Wrong')
@@ -596,7 +595,7 @@ class StorageAPITest(TestCase):
self._set_side_effect('get_record', [record])
with self.storage_api.delete_record(context, 123) as q:
- self.assertEquals(record, q)
+ self.assertEqual(record, q)
self._assert_called_with('delete_record', context, 123)
@@ -606,7 +605,7 @@ class StorageAPITest(TestCase):
self._set_side_effect('get_record', [record])
- with self.assertRaises(SentinelException):
+ with testtools.ExpectedException(SentinelException):
with self.storage_api.delete_record(context, 123):
raise SentinelException('Something Went Wrong')
diff --git a/designate/tests/test_storage/test_sqlalchemy.py b/designate/tests/test_storage/test_sqlalchemy.py
index 859cc72f..b0c470d2 100644
--- a/designate/tests/test_storage/test_sqlalchemy.py
+++ b/designate/tests/test_storage/test_sqlalchemy.py
@@ -19,6 +19,8 @@ from migrate.versioning import api as versioning_api
from migrate.versioning import repository
import sqlalchemy
from designate.openstack.common import log as logging
+from designate import storage
+from designate.tests import TestCase
from designate.tests.test_storage import StorageTestCase
LOG = logging.getLogger(__name__)
@@ -27,21 +29,18 @@ REPOSITORY = os.path.abspath(os.path.join(os.path.dirname(__file__), '..',
'migrate_repo'))
-class SqlalchemyStorageTest(StorageTestCase):
- __test__ = True
-
+class SqlalchemyStorageTest(StorageTestCase, TestCase):
def setUp(self):
self.config(database_connection='sqlite://',
group='storage:sqlalchemy')
super(SqlalchemyStorageTest, self).setUp()
-
+ self.storage = storage.get_storage()
self.REPOSITORY = repository.Repository(REPOSITORY)
# Migration Test Stuff
def _init_database(self, url):
LOG.debug('Building Engine')
engine = sqlalchemy.create_engine(url)
-
LOG.debug('Initializing database')
versioning_api.version_control(engine, repository=self.REPOSITORY)
diff --git a/designate/tests/test_utils.py b/designate/tests/test_utils.py
index 0b554eb7..d1590a7e 100644
--- a/designate/tests/test_utils.py
+++ b/designate/tests/test_utils.py
@@ -15,6 +15,7 @@
# under the License.
import os
import tempfile
+import testtools
from jinja2 import Template
from designate.tests import TestCase
from designate import exceptions
@@ -32,7 +33,7 @@ class TestUtils(TestCase):
def test_resource_string_missing(self):
name = 'invalid.jinja2'
- with self.assertRaises(exceptions.ResourceNotFound):
+ with testtools.ExpectedException(exceptions.ResourceNotFound):
utils.resource_string(name)
def test_load_schema(self):
@@ -41,7 +42,7 @@ class TestUtils(TestCase):
self.assertIsInstance(schema, dict)
def test_load_schema_missing(self):
- with self.assertRaises(exceptions.ResourceNotFound):
+ with testtools.ExpectedException(exceptions.ResourceNotFound):
utils.load_schema('v1', 'missing')
def test_load_template(self):
@@ -54,7 +55,7 @@ class TestUtils(TestCase):
def test_load_template_missing(self):
name = 'invalid.jinja2'
- with self.assertRaises(exceptions.ResourceNotFound):
+ with testtools.ExpectedException(exceptions.ResourceNotFound):
utils.load_template(name)
def test_render_template(self):
diff --git a/openstack-common.conf b/openstack-common.conf
index 12300032..f62ce3e4 100644
--- a/openstack-common.conf
+++ b/openstack-common.conf
@@ -12,6 +12,7 @@ module=processutils
module=rootwrap
module=rpc
module=service
+module=test
module=timeutils
module=uuidutils
module=wsgi
diff --git a/test-requirements.txt b/test-requirements.txt
index c3cf09c4..316393df 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,13 +1,13 @@
coverage>=3.6
+discover
flake8==2.0
-hacking>=0.5.6,<0.8
+fixtures>=0.3.14
+hacking>=0.8,<0.9
mock>=1.0
mox>=0.5.3
-nose
-nosehtmloutput>=0.0.3
-nosexcover
-openstack.nose_plugin>=0.7
pep8==1.4.5
pyflakes>=0.7.2,<0.7.4
-unittest2
+python-subunit
+testtools>=0.9.32
+testrepository>=0.0.8
WebTest>=2.0
diff --git a/tox.ini b/tox.ini
index 95b074a4..004e0fee 100644
--- a/tox.ini
+++ b/tox.ini
@@ -7,24 +7,14 @@ skipsdist = True
downloadcache = ~/cache/pip
[testenv]
-sitepackages = False
usedevelop = True
install_command = pip install {opts} {packages}
deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
-setenv = VIRTUAL_ENV={envdir}
- NOSE_WITH_OPENSTACK=1
- NOSE_OPENSTACK_COLOR=1
- NOSE_OPENSTACK_RED=0.05
- NOSE_OPENSTACK_YELLOW=0.025
- NOSE_OPENSTACK_SHOW_ELAPSED=1
-commands = nosetests {posargs}
+commands = python setup.py testr --slowest --testr-args='{posargs}'
[testenv:cover]
-setenv = {[testenv]setenv}
- NOSE_WITH_COVERAGE=1
- NOSE_COVER_PACKAGE=designate
- NOSE_COVER_INCLUSIVE=1
+commands = python setup.py testr --coverage --testr-args='{posargs}'
[testenv:flake8]
commands = flake8