| import functools |
| import unittest |
| from distutils.version import LooseVersion |
| |
| from nose.plugins.attrib import attr |
| from nose.tools import assert_in, assert_is_instance |
| |
| from dtest import DISABLE_VNODES |
| |
| |
| class since(object): |
| |
| def __init__(self, cass_version, max_version=None): |
| self.cass_version = LooseVersion(cass_version) |
| self.max_version = max_version |
| if self.max_version is not None: |
| self.max_version = LooseVersion(self.max_version) |
| |
| def _skip_msg(self, version): |
| if version < self.cass_version: |
| return "%s < %s" % (version, self.cass_version) |
| if self.max_version and version > self.max_version: |
| return "%s > %s" % (version, self.max_version) |
| |
| def _wrap_setUp(self, cls): |
| orig_setUp = cls.setUp |
| |
| @functools.wraps(cls.setUp) |
| def wrapped_setUp(obj, *args, **kwargs): |
| obj.max_version = self.max_version |
| orig_setUp(obj, *args, **kwargs) |
| version = obj.cluster.version() |
| msg = self._skip_msg(version) |
| if msg: |
| obj.skip(msg) |
| |
| cls.setUp = wrapped_setUp |
| return cls |
| |
| def _wrap_function(self, f): |
| @functools.wraps(f) |
| def wrapped(obj): |
| obj.max_version = self.max_version |
| version = obj.cluster.version() |
| msg = self._skip_msg(version) |
| if msg: |
| obj.skip(msg) |
| f(obj) |
| return wrapped |
| |
| def __call__(self, skippable): |
| if isinstance(skippable, type): |
| return self._wrap_setUp(skippable) |
| return self._wrap_function(skippable) |
| |
| |
| def no_vnodes(): |
| """ |
| Skips the decorated test or test class if using vnodes. |
| """ |
| return unittest.skipIf(not DISABLE_VNODES, 'Test disabled for vnodes') |
| |
| |
| def known_failure(failure_source, jira_url, flaky=False, notes=''): |
| """ |
| Tag a test as a known failure. Associate it with the URL for a JIRA |
| ticket and tag it as flaky or not. |
| |
| Valid values for failure_source include: 'cassandra', 'test', 'driver', and |
| 'systemic'. |
| |
| To run all known failures, use the functionality provided by the nosetests |
| attrib plugin, using the known_failure attributes: |
| |
| # only run tests that are known to fail |
| $ nosetests -a known_failure |
| # only run tests that are not known to fail |
| $ nosetests -a !known_failure |
| # only run tests that fail because of cassandra bugs |
| $ nosetests -A "'cassandra' in [d['failure_source'] for d in known_failure]" |
| |
| Known limitations: a given test may only be tagged once and still work as |
| expected with the attrib plugin machinery; if you decorate a test with |
| known_failure multiple times, the known_failure attribute of that test |
| will have the value applied by the outermost instance of the decorator. |
| """ |
| valid_failure_sources = ('cassandra', 'test', 'systemic', 'driver') |
| |
| def wrapper(f): |
| assert_in(failure_source, valid_failure_sources) |
| assert_is_instance(flaky, bool) |
| |
| try: |
| existing_failure_annotations = f.known_failure |
| except AttributeError: |
| existing_failure_annotations = [] |
| |
| new_annotation = [{'failure_source': failure_source, 'jira_url': jira_url, 'notes': notes, 'flaky': flaky}] |
| |
| failure_annotations = existing_failure_annotations + new_annotation |
| |
| tagged_func = attr(known_failure=failure_annotations)(f) |
| |
| return tagged_func |
| |
| return wrapper |