Merge lp:~thomir-deactivatedaccount/pyruntest/fix-running into lp:pyruntest

Proposed by Thomi Richards
Status: Merged
Approved by: Martin Mrazik
Approved revision: 11
Merged at revision: 7
Proposed branch: lp:~thomir-deactivatedaccount/pyruntest/fix-running
Merge into: lp:pyruntest
Diff against target: 219 lines (+106/-12)
3 files modified
pyruntest (+52/-9)
setup.py (+9/-1)
tests.py (+45/-2)
To merge this branch: bzr merge lp:~thomir-deactivatedaccount/pyruntest/fix-running
Reviewer Review Type Date Requested Status
jenkins (community) continuous-integration Needs Fixing
Christopher Lee (community) Approve
Review via email: mp+124331@code.launchpad.net

Commit message

Run tests from both within a python package and from outside it.

Description of the change

This branch merges a couple of martin's proposed branches, adds tests, and adds a few other bug-fixes.

The overall purpose is to ensure that we can run tests both within a package and from outside the package.

To post a comment you must log in.
Revision history for this message
jenkins (martin-mrazik+qa) wrote :
review: Approve (continuous-integration)
Revision history for this message
Christopher Lee (veebers) wrote :

Looks good.

review: Approve
Revision history for this message
jenkins (martin-mrazik+qa) wrote :

FAILED: Autolanding.
More details in the following jenkins job:
http://s-jenkins:8080/job/pyruntest-autolanding/1/

review: Needs Fixing (continuous-integration)
Revision history for this message
jenkins (martin-mrazik+qa) wrote :

FAILED: Autolanding.
More details in the following jenkins job:
http://s-jenkins:8080/job/pyruntest-autolanding/2/

review: Needs Fixing (continuous-integration)
Revision history for this message
jenkins (martin-mrazik+qa) wrote :

FAILED: Autolanding.
More details in the following jenkins job:
http://s-jenkins:8080/job/pyruntest-autolanding/3/

review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'pyruntest'
2--- pyruntest 2012-09-12 21:17:03 +0000
3+++ pyruntest 2012-09-14 02:26:23 +0000
4@@ -13,15 +13,22 @@
5 import argparse
6 from argparse import ArgumentParser
7 from contextlib import contextmanager
8+import logging
9 import sys
10+from testtools import iterate_tests
11 from unittest.loader import TestLoader
12 from unittest import TestSuite
13-from testtools import iterate_tests
14+import os
15+
16+
17+logger = logging.getLogger(__name__)
18+_output_stream = None
19
20
21 def main():
22 args = parse_args()
23
24+ logging.basicConfig(stream=get_output_stream(args))
25 test_suite = load_test_suite_from_name(args.suite)
26 runner = construct_test_runner(args)
27 success = runner.run(test_suite).wasSuccessful()
28@@ -29,8 +36,29 @@
29 exit(1)
30
31
32+def get_output_stream(args):
33+ global _output_stream
34+
35+ if _output_stream is None:
36+ if args.output:
37+ _output_stream = open(args.output, 'w')
38+ else:
39+ _output_stream = sys.stdout
40+ return _output_stream
41+
42+
43+def patch_python_path():
44+ """Prepend the current directory to sys.path to ensure that we can
45+ load & run tests if the caller is in the parent directory.
46+
47+ """
48+ if os.getcwd() not in sys.path:
49+ sys.path.insert(0, os.getcwd())
50+
51+
52 def load_test_suite_from_name(test_names):
53 """Returns a test suite object given a dotted test names."""
54+ patch_python_path()
55 loader = TestLoader()
56 if isinstance(test_names, basestring):
57 test_names = list(test_names)
58@@ -39,12 +67,30 @@
59 % (type(test_names)))
60
61 tests = []
62-
63+ test_package_locations = []
64 for test_name in test_names:
65 top_level_pkg = test_name.split('.')[0]
66- tests.append(loader.discover(top_level_pkg))
67+ package = __import__(top_level_pkg)
68+ pkg_file = package.__file__
69+ if os.path.basename(pkg_file).startswith('__init__'):
70+ package_parent_path = os.path.abspath(
71+ os.path.join(
72+ os.path.dirname(pkg_file),
73+ '..'
74+ )
75+ )
76+ else:
77+ package_parent_path = os.path.abspath(os.path.dirname(pkg_file))
78+ if package_parent_path not in test_package_locations:
79+ test_package_locations.append(package_parent_path)
80+
81+ tests.append(loader.discover(top_level_pkg,
82+ top_level_dir=package_parent_path))
83 all_tests = TestSuite(tests)
84
85+ test_dirs = ", ".join(sorted(test_package_locations))
86+ logger.info("Loading tests from: %s\n", test_dirs)
87+
88 requested_tests = {}
89 for test in iterate_tests(all_tests):
90 # The test loader returns tests that start with 'unittest.loader' if for
91@@ -64,9 +110,7 @@
92
93
94 def construct_test_runner(args):
95- output_stream = sys.stdout
96- if args.output:
97- output_stream = open(args.output, 'w')
98+ output_stream = get_output_stream(args)
99
100 kwargs = dict(stdout=output_stream,
101 output_format=args.format
102@@ -96,8 +140,8 @@
103 self.result_class = output_format
104 self.coverage = coverage
105 self.cover_format = cover_format
106- self.cover_output=cover_output
107- self.cover_exclude=cover_exclude.split(',')
108+ self.cover_output = cover_output
109+ self.cover_exclude = cover_exclude.split(',')
110
111 def run(self, test):
112 "Run the given test case or test suite."
113@@ -135,7 +179,6 @@
114 cov.report(file=open(filename, 'w'))
115
116
117-
118 class FormatAction(argparse.Action):
119 """An Argparse action that stores the output format class object."""
120
121
122=== modified file 'setup.py'
123--- setup.py 2012-09-12 12:08:31 +0000
124+++ setup.py 2012-09-14 02:26:23 +0000
125@@ -1,3 +1,11 @@
126+# Copyright 2012 Canonical
127+# Author: Thomi Richards
128+#
129+# This program is free software: you can redistribute it and/or modify it
130+# under the terms of the GNU General Public License version 3, as published
131+# by the Free Software Foundation.
132+#
133+
134 from setuptools import setup
135
136 setup(
137@@ -6,7 +14,7 @@
138 description='Python script for running python tests.',
139 author='Thomi Richards',
140 author_email='thomi.richards@canonical.com',
141- url='https://launchpad.net/pytestrunner',
142+ url='https://launchpad.net/pyruntest',
143 license='GPLv3',
144 scripts=['pyruntest', ],
145 )
146
147=== modified file 'tests.py'
148--- tests.py 2012-09-12 21:17:03 +0000
149+++ tests.py 2012-09-14 02:26:23 +0000
150@@ -13,6 +13,7 @@
151 import os.path
152 from shutil import rmtree
153 import subprocess
154+from tempfile import mkdtemp
155 from testtools import TestCase
156 from testtools.matchers import Equals, NotEquals, Contains, Not
157 from textwrap import dedent
158@@ -35,13 +36,37 @@
159 '''))
160 self.addCleanup(remove, 'test_empty.py')
161
162- def run_script(self, *args):
163+ def create_test_package(self):
164+ location = mkdtemp()
165+ self.addCleanup(rmtree, location)
166+ open(os.path.join(location, '__init__.py'), 'w').write('#')
167+ os.mkdir(os.path.join(location, 'tests'))
168+ open(os.path.join(location, 'tests', '__init__.py'), 'w').write('#')
169+ open(os.path.join(location, 'tests', 'test_empty.py'), 'w').write(
170+ dedent('''\
171+
172+ from testtools import TestCase
173+
174+
175+ class SimpleTests(TestCase):
176+
177+ def test_simple(self):
178+ self.assertEqual(1,1)
179+
180+ '''))
181+ return location
182+
183+ def run_script(self, *args, **kwargs):
184 arguments = ['./pyruntest']
185 arguments.extend(args)
186
187+ if 'cwd' in kwargs:
188+ arguments[0] = os.path.abspath('./pyruntest')
189+
190 process = subprocess.Popen(arguments,
191 stdout=subprocess.PIPE,
192- stderr=subprocess.PIPE
193+ stderr=subprocess.PIPE,
194+ **kwargs
195 )
196 stdout, stderr = process.communicate()
197 return (stdout, stderr, process.poll())
198@@ -155,3 +180,21 @@
199 remove('coverage.xml')
200 out, err, code = self.run_script('-c', '-cf', 'xml', '-ce', '/usr*', 'test_empty')
201 self.assertThat(open('coverage.xml').read(), Not(Contains('/usr/')))
202+
203+ def test_can_run_from_inside_package(self):
204+ location = self.create_test_package()
205+ out, err, code = self.run_script('tests', cwd=location)
206+
207+ self.assertThat(code, Equals(0))
208+ self.assertThat(err, Equals(''))
209+ self.assertThat(out, Contains('Ran 1 test in'))
210+
211+ def test_can_run_from_outside_package(self):
212+ location = self.create_test_package()
213+ pkg_name = location.split(os.path.sep)[-1]
214+ parent_dir = os.path.sep.join(location.split(os.path.sep)[:-1])
215+ out, err, code = self.run_script(pkg_name, cwd=parent_dir)
216+
217+ self.assertThat(code, Equals(0))
218+ self.assertThat(err, Equals(''))
219+ self.assertThat(out, Contains('Ran 1 test in'))

Subscribers

People subscribed via source and target branches

to all changes: