summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COPYING1
-rw-r--r--NEWS7
-rw-r--r--doc/MANUAL.txt20
-rwxr-xr-xsetup.py5
-rw-r--r--testrepository/setuptools_command.py94
5 files changed, 126 insertions, 1 deletions
diff --git a/COPYING b/COPYING
index d3fae84..daebc89 100644
--- a/COPYING
+++ b/COPYING
@@ -28,6 +28,7 @@ A concordance of contributors is maintained here to provide an easy reference
for distributions such as Debian that wish to list all the copyright holders
in their metadata:
* Robert Collins <robertc@robertcollins.net>, 2009
+* Hewlett-Packard Development Company, L.P., 2013
Code that has been incorporated into Testrepository from other projects will
diff --git a/NEWS b/NEWS
index 6c4ef94..906cc4e 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,13 @@ testrepository release notes
NEXT (In development)
+++++++++++++++++++++
+IMPROVEMENTS
+------------
+
+* There is now a setuptools extension provided by ``testrespository`` making it
+ easy to invoke testr from setup.py driven workflows.
+ (Monty Taylor, Robert Collins)
+
INTERNALS
---------
diff --git a/doc/MANUAL.txt b/doc/MANUAL.txt
index e81d470..16bbe80 100644
--- a/doc/MANUAL.txt
+++ b/doc/MANUAL.txt
@@ -232,7 +232,7 @@ The process testr follows is:
The provisioning callout needs to synchronise source code and do any other
per-instance setup at this stage.
5. testr will make callouts to execute tests, supplying files that should be
- copied into the execution environment. Note that instances may be used for
+ copied into the execution environment. Note that instances may be used for
more than one command execution.
6. testr will callout to dispose of the instances after the test run completes.
@@ -366,3 +366,21 @@ files (for a format 1 repository - the only current format):
* repo.conf: This file contains user configuration settings for the repository.
``testr repo-config`` will dump a repo configration and
``test help repo-config`` has online help for all the repository settings.
+
+setuptools integration
+~~~~~~~~~~~~~~~~~~~~~~
+
+testrepository provides a setuptools commands for ease of integration with
+setuptools-based workflows:
+
+* testr:
+ ``python setup.py testr`` will run testr in parallel mode
+ Options that would normally be passed to testr run can be added to the
+ testr-options argument.
+ ``python setup.py testr --testr-options="--failing"`` will append --failing
+ to the test run.
+* testr --coverage:
+ ``python setup.py testr --coverage`` will run testr in code coverage mode. This
+ assumes the installation of the python coverage module.
+* ``python testr --coverage --omit=ModuleThatSucks.py`` will append
+ --omit=ModuleThatSucks.py to the coverage report command.
diff --git a/setup.py b/setup.py
index dada42f..0c3bc38 100755
--- a/setup.py
+++ b/setup.py
@@ -106,4 +106,9 @@ setup(name='testrepository',
'testscenarios',
]
),
+ entry_points={
+ 'distutils.commands': [
+ 'testr = testrepository.setuptools_command:Testr',
+ ],
+ },
)
diff --git a/testrepository/setuptools_command.py b/testrepository/setuptools_command.py
new file mode 100644
index 0000000..bfb5277
--- /dev/null
+++ b/testrepository/setuptools_command.py
@@ -0,0 +1,94 @@
+#
+# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
+# Copyright (c) 2013 Testrepository Contributors
+#
+# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
+# license at the users choice. A copy of both licenses are available in the
+# project source as Apache-2.0 and BSD. You may not use this file except in
+# compliance with one of these two licences.
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# license you chose for the specific language governing permissions and
+# limitations under that license.
+
+"""setuptools/distutils commands to run testr via setup.py
+
+Currently provides 'testr' which runs tests using testr. You can pass
+--coverage which will also export PYTHON='coverage run --source <your package>'
+and automatically combine the coverage from each testr backend test runner
+after the run completes.
+
+To use, just use setuptools/distribute and depend on testr, and it should be
+picked up automatically (as the commands are exported in the testrepository
+package metadata.
+"""
+
+from distutils import cmd
+import distutils.errors
+import os
+import sys
+
+from testrepository import commands
+
+
+class Testr(cmd.Command):
+
+ description = "Run unit tests using testr"
+
+ user_options = [
+ ('coverage', None, "Replace PYTHON with coverage and merge coverage "
+ "from each testr worker."),
+ ('testr-args=', 't', "Run 'testr' with these args"),
+ ('omit=', 'o', 'Files to omit from coverage calculations'),
+ ('slowest', None, "Show slowest test times after tests complete."),
+ ]
+
+ boolean_options = ['coverage', 'slowest']
+
+ def _run_testr(self, *args):
+ commands.run_argv([sys.argv[0]] + list(args),
+ sys.stdin, sys.stdout, sys.stderr)
+
+ def initialize_options(self):
+ self.testr_args = None
+ self.coverage = None
+ self.omit = ""
+ self.slowest = None
+
+ def finalize_options(self):
+ if self.testr_args is None:
+ self.testr_args = []
+ else:
+ self.testr_args = self.testr_args.split()
+ if self.omit:
+ self.omit = "--omit=%s" % self.omit
+
+ def run(self):
+ """Set up testr repo, then run testr"""
+ if not os.path.isdir(".testrepository"):
+ self._run_testr("init")
+
+ if self.coverage:
+ self._coverage_before()
+ testr_ret = self._run_testr("run", "--parallel", *self.testr_args)
+ if testr_ret:
+ raise distutils.errors.DistutilsError(
+ "testr failed (%d)" % testr_ret)
+ if self.slowest:
+ print "Slowest Tests"
+ self._run_testr("slowest")
+ if self.coverage:
+ self._coverage_after()
+
+ def _coverage_before(self):
+ package = self.distribution.get_name()
+ if package.startswith('python-'):
+ package = package[7:]
+ options = "--source %s --parallel-mode" % package
+ os.environ['PYTHON'] = ("coverage run %s" % options)
+
+ def _coverage_after(self):
+ os.system("coverage combine")
+ os.system("coverage html -d ./cover %s" % self.omit)