summaryrefslogtreecommitdiffstats
path: root/testsuite/common.py
diff options
context:
space:
mode:
authorChris St. Pierre <chris.a.st.pierre@gmail.com>2012-08-22 14:12:52 -0400
committerChris St. Pierre <chris.a.st.pierre@gmail.com>2012-08-22 14:12:52 -0400
commitffe423ab49a5effb2626fae4828e1542462808c9 (patch)
treedd071a3de13ad458478e96dc6102eb11948862e3 /testsuite/common.py
parente25d446c9f51a178285b55ac230468aecfcb660e (diff)
downloadbcfg2-ffe423ab49a5effb2626fae4828e1542462808c9.tar.gz
bcfg2-ffe423ab49a5effb2626fae4828e1542462808c9.tar.bz2
bcfg2-ffe423ab49a5effb2626fae4828e1542462808c9.zip
fixed patchIf() (I hope)
Diffstat (limited to 'testsuite/common.py')
-rw-r--r--testsuite/common.py77
1 files changed, 59 insertions, 18 deletions
diff --git a/testsuite/common.py b/testsuite/common.py
index 49c287a70..5b1799d91 100644
--- a/testsuite/common.py
+++ b/testsuite/common.py
@@ -1,7 +1,7 @@
import os
import sys
import unittest
-from mock import patch
+from mock import patch, MagicMock, _patch, DEFAULT
from functools import wraps
datastore = "/"
@@ -204,8 +204,8 @@ class DBModelTestCase(Bcfg2TestCase):
@skipUnless(has_django, "Django not found, skipping")
def test_cleandb(self):
- """ ensure that we a) can connect to the database; b) start with a
- clean database """
+ # ensure that we a) can connect to the database; b) start with
+ # a clean database
for model in self.models:
model.objects.all().delete()
self.assertItemsEqual(list(model.objects.all()), [])
@@ -217,7 +217,18 @@ def syncdb(modeltest):
inst.test_cleandb()
-def patchIf(condition, entity, **kwargs):
+# in order for patchIf() to decorate a function in the same way as
+# patch(), we override the default behavior of __enter__ and __exit__
+# on the _patch() object to basically be noops.
+class _noop_patch(_patch):
+ def __enter__(self):
+ return MagicMock(name=self.attribute)
+
+ def __exit__(self, *args):
+ pass
+
+
+class patchIf(object):
""" perform conditional patching. this is necessary because some
libraries might not be installed (e.g., selinux, pylibacl), and
patching will barf on that. Other workarounds are not available
@@ -225,17 +236,47 @@ def patchIf(condition, entity, **kwargs):
inner functions doesn't work because python 2.6 applies all
decorators at compile-time, not at run-time, so decorating inner
functions does not prevent the decorators from being run. """
- if condition:
- return patch(entity, **kwargs)
- elif "new" in kwargs:
- # new object provided, so no argument is added to the function call
- return lambda f: f
- else:
- # need to add an argument to the function call
- def decorator(func):
- @wraps(func)
- def inner(*args, **kwargs):
- args = list(args) + [None]
- return func(*args, **kwargs)
- return inner
- return decorator
+ def __init__(self, condition, target, new=DEFAULT, spec=None, create=False,
+ spec_set=None, autospec=None, new_callable=None, **kwargs):
+ self.condition = condition
+ self.target = target
+ self.patch_args = dict(new=new, spec=spec, create=create,
+ spec_set=spec_set)
+ self.extra_patch_args = dict(autospec=autospec,
+ new_callable=new_callable)
+ self.kwargs = kwargs
+
+ def __call__(self, func):
+ if self.condition:
+ try:
+ # in newer versions of mock, patch() takes arbitrary
+ # keyword arguments
+ args = dict(**self.patch_args)
+ args.update(self.extra_patch_args)
+ args.update(self.kwargs)
+ return patch(self.target, **args)(func)
+ except TypeError:
+ # in older versions of mock, patch() doesn't take
+ # autospec, new_callable or arbitrary keyword
+ # arguments
+ return patch(self.target, **self.patch_args)(func)
+ else:
+ try:
+ args = [lambda: True,
+ self.target.rsplit('.', 1)[-1],
+ self.patch_args['new'], self.patch_args['spec'],
+ self.patch_args['create'], None,
+ self.patch_args['spec_set']]
+ # in older versions of mock _patch() takes 8 args
+ return _noop_patch(*args)(func)
+ except TypeError:
+ # in new versions of mock _patch() takes 10 args
+ args = [lambda: True,
+ self.target.rsplit('.', 1)[-1],
+ self.patch_args['new'], self.patch_args['spec'],
+ self.patch_args['create'], self.patch_args['spec_set'],
+ self.extra_patch_args['autospec'],
+ self.extra_patch_args['new_callable'],
+ self.kwargs]
+ return _noop_patch(*args)(func)
+