[conduit: 89/138] Add EnvironmentWrapper objects. Allows us to avoid spaghetti for profilers, coverage checks and (eep
- From: John Carr <johncarr src gnome org>
- To: svn-commits-list gnome org
- Subject: [conduit: 89/138] Add EnvironmentWrapper objects. Allows us to avoid spaghetti for profilers, coverage checks and (eep
- Date: Thu, 21 May 2009 03:34:24 -0400 (EDT)
commit e220f2f8a6e86ad1a86e4a09acf942c0438c2504
Author: John Carr <john carr unrouted co uk>
Date: Mon May 4 12:50:57 2009 -0700
Add EnvironmentWrapper objects. Allows us to avoid spaghetti for profilers, coverage checks and (eep) custom dbus sessions
---
test/soup/env/__init__.py | 44 ++++++++++++++++++++++++++++++++++++++++++++
test/soup/env/cov.py | 34 ++++++++++++++++++++++++++++++++++
test/soup/env/profile.py | 29 +++++++++++++++++++++++++++++
test/soup/result.py | 33 +++++++++++++++++++++++++++++++--
test/soup/soup | 26 ++++++++------------------
5 files changed, 146 insertions(+), 20 deletions(-)
diff --git a/test/soup/env/__init__.py b/test/soup/env/__init__.py
new file mode 100644
index 0000000..d7f7c34
--- /dev/null
+++ b/test/soup/env/__init__.py
@@ -0,0 +1,44 @@
+
+import os, sys
+
+class EnvironmentWrapper(object):
+
+ @classmethod
+ def enabled(cls, opts):
+ return True
+
+ def prepare_environment(self):
+ """ Modify the environment that the tests are running in """
+ pass
+
+ def decorate_test(self, test):
+ """ Decorate a callable so that it can be run in the modified environment """
+ return test
+
+ def finalize_environment(self):
+ """ Clean up the environment. Called at the very end of the test suite. """
+ pass
+
+
+def load_modules():
+ basepath = os.path.dirname(__file__)
+ for root, dirs, files in os.walk(basepath):
+ for dir in dirs:
+ if dir[:1] != ".":
+ load_module(dir)
+ for file in files:
+ if file.endswith(".py") and not file.startswith("__"):
+ load_module(file[:-3])
+ break
+
+def load_module(module):
+ if sys.modules.has_key(module):
+ reload(sys.modules[module])
+ else:
+ __import__("soup.env", {}, {}, [module])
+
+def get_all():
+ if len(EnvironmentWrapper.__subclasses__()) == 0:
+ load_modules()
+ return EnvironmentWrapper.__subclasses__()
+
diff --git a/test/soup/env/cov.py b/test/soup/env/cov.py
new file mode 100644
index 0000000..8fc656b
--- /dev/null
+++ b/test/soup/env/cov.py
@@ -0,0 +1,34 @@
+
+import soup
+
+try:
+ import coverage
+ supports_coverage = True
+except:
+ supports_coverage = False
+
+from glob import glob
+
+
+class Coverage(soup.env.EnvironmentWrapper):
+
+ @classmethod
+ def enabled(cls, opts):
+ if not opts.coverage:
+ return False
+ #FIXME: Should try importing and fail gracefully if user requests
+ # coverage but cant have it
+ assert supports_coverage
+ return True
+
+ def prepare_environment(self):
+ import coverage
+ coverage.erase()
+ coverage.start()
+
+ def finalize_environment(self):
+ coverage.stop()
+ modules = glob("conduit/*.py") + glob("conduit/*/*.py") + glob("conduit/*/*/*.py")
+ coverage.report(modules, ignore_errors=1, show_missing=0)
+ coverage.erase()
+
diff --git a/test/soup/env/profile.py b/test/soup/env/profile.py
new file mode 100644
index 0000000..502c3d4
--- /dev/null
+++ b/test/soup/env/profile.py
@@ -0,0 +1,29 @@
+
+import soup
+
+try:
+ import cProfile
+ import pstats
+ supported = True
+except ImportError:
+ supported = False
+
+
+class Profile(soup.env.EnvironmentWrapper):
+
+ @classmethod
+ def enabled(self, opts):
+ if not opts.profile:
+ return False
+ assert supported, "You need python-profiler to profile the test cases"
+ return True
+
+ def decorate_test(self, test):
+ def _(*args, **kwargs):
+ p = cProfile.Profile()
+ res = p.runcall(test, *args, **kwargs)
+ #FIXME: Need some way to attach profiling data to report object
+ # p.print_stats()
+ return res
+ return _
+
diff --git a/test/soup/result.py b/test/soup/result.py
index f7251f9..da2ea55 100644
--- a/test/soup/result.py
+++ b/test/soup/result.py
@@ -1,4 +1,5 @@
+import soup.env
from soup import UnavailableFeature
from soup.utils import progressbar
@@ -140,11 +141,17 @@ class VerboseConsoleTextResult(TextTestResult):
class TestRunner(object):
- def __init__(self, stream=sys.stderr, descriptions=0, verbosity=1):
+ def __init__(self, opts, stream=sys.stderr, descriptions=0, verbosity=1):
self.stream = unittest._WritelnDecorator(stream)
self.descriptions = 0
self.verbosity = 0
+ # Discover all enabled EnvironmentWrapper objects
+ self.env = []
+ for e in soup.env.get_all():
+ if e.enabled(opts):
+ self.env.append(e())
+
def make_results(self, tests):
if self.verbosity > 1:
klass = VerboseConsoleTextResult
@@ -153,12 +160,34 @@ class TestRunner(object):
return klass(self.stream, self.descriptions, self.verbosity, num_tests=tests.countTestCases())
+ def iter_tests(self, tests):
+ if isinstance(tests, unittest.TestSuite):
+ for test in tests:
+ for subtest in self.iter_tests(test):
+ yield subtest
+ else:
+ yield tests
+
def run(self, tests):
result = self.make_results(tests)
result.report_starting()
+
+ for e in self.env:
+ e.prepare_environment()
+
start_time = time.time()
- tests.run(result)
+
+ for t in self.iter_tests(tests):
+ tr = t.run
+ for e in self.env:
+ tr = e.decorate_test(tr)
+ tr(result)
+
time_taken = time.time() - start_time
+
+ for e in self.env:
+ e.finalize_environment()
+
result.report_finished(time_taken)
return result
diff --git a/test/soup/soup b/test/soup/soup
index 9fa679a..510c029 100755
--- a/test/soup/soup
+++ b/test/soup/soup
@@ -1,7 +1,6 @@
#! /usr/bin/env python
import sys, os, unittest, logging
-from glob import glob
testsdir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
sys.path.insert(0, testsdir)
@@ -24,28 +23,17 @@ from test_synchronization import *
import result
-def run_tests(tests, verbose=False, do_coverage=False):
- runner = result.TestRunner(verbosity=2 if verbose else 1)
+def run_tests(tests, opts):
+ runner = result.TestRunner(opts)
- if verbose:
+ if opts.verbose:
logging.basicConfig(level=logging.DEBUG)
- if do_coverage:
- import coverage
- coverage.erase()
- coverage.start()
-
res = runner.run(unittest.TestSuite(tests))
- if do_coverage:
- coverage.stop()
- modules = glob('conduit/*.py')+glob('conduit/*/*.py')+glob('conduit/*/*/*.py')
- coverage.report(modules, ignore_errors=1, show_missing=0)
- coverage.erase()
-
sys.exit(not res.wasSuccessful())
-def list_tests(tests):
+def list_tests(tests, opts):
for test in tests:
print test.name(), test.testMethodName
sys.exit(0)
@@ -67,6 +55,8 @@ if __name__ == "__main__":
help="Output lots of noise as tests are run")
parser.add_option("-c", "--coverage", action="store_true", dest="coverage",
help="Enable code coverage")
+ parser.add_option("-p", "--profile", action="store_true", dest="profile",
+ help="Profile execution")
# Add the different execution modes..
parser.add_option("-l", "--list", action="store_const", const="list", dest="mode",
@@ -90,7 +80,7 @@ if __name__ == "__main__":
# And run.
if opts.mode == "execute":
- run_tests(tests, verbose=opts.verbose, do_coverage=opts.coverage)
+ run_tests(tests, opts)
elif opts.mode == "list":
- list_tests(tests)
+ list_tests(tests, opts)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]