1
# Copyright (C) 2005 by Canonical Ltd
1
# Copyright (C) 2005, 2006 by Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
11
# GNU General Public License for more details.
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
# TODO: Perhaps there should be an API to find out if bzr running under the
19
# test suite -- some plugins might want to avoid making intrusive changes if
20
# this is the case. However, we want behaviour under to test to diverge as
21
# little as possible, so this should be used rarely if it's added at all.
22
# (Suggestion from j-a-meinel, 2005-11-24)
24
# NOTE: Some classes in here use camelCaseNaming() rather than
25
# underscore_naming(). That's for consistency with unittest; it's not the
26
# general style of bzrlib. Please continue that consistency when adding e.g.
27
# new assertFoo() methods.
18
30
from cStringIO import StringIO
39
from subprocess import Popen, PIPE
46
from bzrlib import memorytree
31
47
import bzrlib.branch
48
import bzrlib.bzrdir as bzrdir
32
49
import bzrlib.commands
33
from bzrlib.errors import BzrError
50
import bzrlib.bundle.serializer
51
import bzrlib.errors as errors
34
53
import bzrlib.inventory
54
import bzrlib.iterablefile
59
# lsprof not available
61
from bzrlib.merge import merge_inner
35
62
import bzrlib.merge3
36
63
import bzrlib.osutils
64
import bzrlib.osutils as osutils
37
65
import bzrlib.plugin
66
import bzrlib.progress as progress
67
from bzrlib.revision import common_ancestor
38
68
import bzrlib.store
69
from bzrlib import symbol_versioning
39
70
import bzrlib.trace
71
from bzrlib.transport import get_transport
72
import bzrlib.transport
73
from bzrlib.transport.local import LocalRelpathServer
74
from bzrlib.transport.readonly import ReadonlyServer
40
75
from bzrlib.trace import mutter
41
from bzrlib.tests.TestUtil import TestLoader, TestSuite
76
from bzrlib.tests import TestUtil
77
from bzrlib.tests.TestUtil import (
42
81
from bzrlib.tests.treeshape import build_tree_contents
82
import bzrlib.urlutils as urlutils
83
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
85
default_transport = LocalRelpathServer
44
87
MODULES_TO_TEST = []
45
88
MODULES_TO_DOCTEST = [
90
bzrlib.bundle.serializer,
54
105
def packages_to_test():
106
"""Return a list of packages to test.
108
The packages are not globally imported so that import failures are
109
triggered when running selftest, not when importing the command.
55
112
import bzrlib.tests.blackbox
113
import bzrlib.tests.branch_implementations
114
import bzrlib.tests.bzrdir_implementations
115
import bzrlib.tests.interrepository_implementations
116
import bzrlib.tests.interversionedfile_implementations
117
import bzrlib.tests.intertree_implementations
118
import bzrlib.tests.repository_implementations
119
import bzrlib.tests.revisionstore_implementations
120
import bzrlib.tests.tree_implementations
121
import bzrlib.tests.workingtree_implementations
124
bzrlib.tests.blackbox,
125
bzrlib.tests.branch_implementations,
126
bzrlib.tests.bzrdir_implementations,
127
bzrlib.tests.interrepository_implementations,
128
bzrlib.tests.interversionedfile_implementations,
129
bzrlib.tests.intertree_implementations,
130
bzrlib.tests.repository_implementations,
131
bzrlib.tests.revisionstore_implementations,
132
bzrlib.tests.tree_implementations,
133
bzrlib.tests.workingtree_implementations,
61
class EarlyStoppingTestResultAdapter(object):
62
"""An adapter for TestResult to stop at the first first failure or error"""
64
def __init__(self, result):
67
def addError(self, test, err):
68
self._result.addError(test, err)
71
def addFailure(self, test, err):
72
self._result.addFailure(test, err)
75
def __getattr__(self, name):
76
return getattr(self._result, name)
78
def __setattr__(self, name, value):
80
object.__setattr__(self, name, value)
81
return setattr(self._result, name, value)
84
137
class _MyResult(unittest._TextTestResult):
85
138
"""Custom TestResult.
87
140
Shows output in a different format, including displaying runtime for tests.
90
def _elapsedTime(self):
91
return "%5dms" % (1000 * (time.time() - self._start_time))
144
def __init__(self, stream, descriptions, verbosity, pb=None,
146
"""Construct new TestResult.
148
:param bench_history: Optionally, a writable file object to accumulate
151
unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
153
if bench_history is not None:
154
from bzrlib.version import _get_bzr_source_tree
155
src_tree = _get_bzr_source_tree()
158
revision_id = src_tree.get_parent_ids()[0]
160
# XXX: if this is a brand new tree, do the same as if there
164
# XXX: If there's no branch, what should we do?
166
bench_history.write("--date %s %s\n" % (time.time(), revision_id))
167
self._bench_history = bench_history
169
def extractBenchmarkTime(self, testCase):
170
"""Add a benchmark time for the current test case."""
171
self._benchmarkTime = getattr(testCase, "_benchtime", None)
173
def _elapsedTestTimeString(self):
174
"""Return a time string for the overall time the current test has taken."""
175
return self._formatTime(time.time() - self._start_time)
177
def _testTimeString(self):
178
if self._benchmarkTime is not None:
180
self._formatTime(self._benchmarkTime),
181
self._elapsedTestTimeString())
183
return " %s" % self._elapsedTestTimeString()
185
def _formatTime(self, seconds):
186
"""Format seconds as milliseconds with leading spaces."""
187
return "%5dms" % (1000 * seconds)
189
def _ellipsise_unimportant_words(self, a_string, final_width,
191
"""Add ellipses (sp?) for overly long strings.
193
:param keep_start: If true preserve the start of a_string rather
197
if len(a_string) > final_width:
198
result = a_string[:final_width-3] + '...'
202
if len(a_string) > final_width:
203
result = '...' + a_string[3-final_width:]
206
return result.ljust(final_width)
93
208
def startTest(self, test):
94
209
unittest.TestResult.startTest(self, test)
96
211
# the beginning, but in an id, the important words are
98
213
SHOW_DESCRIPTIONS = False
215
if not self.showAll and self.dots and self.pb is not None:
218
final_width = osutils.terminal_width()
219
final_width = final_width - 15 - 8
221
if SHOW_DESCRIPTIONS:
222
what = test.shortDescription()
224
what = self._ellipsise_unimportant_words(what, final_width, keep_start=True)
227
if what.startswith('bzrlib.tests.'):
229
what = self._ellipsise_unimportant_words(what, final_width)
100
width = bzrlib.osutils.terminal_width()
101
name_width = width - 15
103
if SHOW_DESCRIPTIONS:
104
what = test.shortDescription()
106
if len(what) > name_width:
107
what = what[:name_width-3] + '...'
110
if what.startswith('bzrlib.tests.'):
112
if len(what) > name_width:
113
what = '...' + what[3-name_width:]
114
what = what.ljust(name_width)
115
231
self.stream.write(what)
232
elif self.dots and self.pb is not None:
233
self.pb.update(what, self.testsRun - 1, None)
116
234
self.stream.flush()
235
self._recordTestStartTime()
237
def _recordTestStartTime(self):
238
"""Record that a test has started."""
117
239
self._start_time = time.time()
119
241
def addError(self, test, err):
242
if isinstance(err[1], TestSkipped):
243
return self.addSkipped(test, err)
120
244
unittest.TestResult.addError(self, test, err)
245
test.setKeepLogfile()
246
self.extractBenchmarkTime(test)
122
self.stream.writeln("ERROR %s" % self._elapsedTime())
248
self.stream.writeln("ERROR %s" % self._testTimeString())
249
elif self.dots and self.pb is None:
124
250
self.stream.write('E')
252
self.pb.update(self._ellipsise_unimportant_words('ERROR', 13), self.testsRun, None)
253
self.pb.note(self._ellipsise_unimportant_words(
254
test.id() + ': ERROR',
255
osutils.terminal_width()))
125
256
self.stream.flush()
127
260
def addFailure(self, test, err):
128
261
unittest.TestResult.addFailure(self, test, err)
262
test.setKeepLogfile()
263
self.extractBenchmarkTime(test)
130
self.stream.writeln(" FAIL %s" % self._elapsedTime())
265
self.stream.writeln(" FAIL %s" % self._testTimeString())
266
elif self.dots and self.pb is None:
132
267
self.stream.write('F')
269
self.pb.update(self._ellipsise_unimportant_words('FAIL', 13), self.testsRun, None)
270
self.pb.note(self._ellipsise_unimportant_words(
271
test.id() + ': FAIL',
272
osutils.terminal_width()))
133
273
self.stream.flush()
135
277
def addSuccess(self, test):
278
self.extractBenchmarkTime(test)
279
if self._bench_history is not None:
280
if self._benchmarkTime is not None:
281
self._bench_history.write("%s %s\n" % (
282
self._formatTime(self._benchmarkTime),
137
self.stream.writeln(' OK %s' % self._elapsedTime())
285
self.stream.writeln(' OK %s' % self._testTimeString())
286
for bench_called, stats in getattr(test, '_benchcalls', []):
287
self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
288
stats.pprint(file=self.stream)
289
elif self.dots and self.pb is None:
139
290
self.stream.write('~')
292
self.pb.update(self._ellipsise_unimportant_words('OK', 13), self.testsRun, None)
140
293
self.stream.flush()
141
294
unittest.TestResult.addSuccess(self, test)
296
def addSkipped(self, test, skip_excinfo):
297
self.extractBenchmarkTime(test)
299
print >>self.stream, ' SKIP %s' % self._testTimeString()
300
print >>self.stream, ' %s' % skip_excinfo[1]
301
elif self.dots and self.pb is None:
302
self.stream.write('S')
304
self.pb.update(self._ellipsise_unimportant_words('SKIP', 13), self.testsRun, None)
306
# seems best to treat this as success from point-of-view of unittest
307
# -- it actually does nothing so it barely matters :)
310
except KeyboardInterrupt:
313
self.addError(test, test.__exc_info())
315
unittest.TestResult.addSuccess(self, test)
143
317
def printErrorList(self, flavour, errors):
144
318
for test, err in errors:
145
319
self.stream.writeln(self.separator1)
146
self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
147
if hasattr(test, '_get_log'):
148
self.stream.writeln()
149
self.stream.writeln('log from this test:')
320
self.stream.writeln("%s: %s" % (flavour, self.getDescription(test)))
321
if getattr(test, '_get_log', None) is not None:
323
print >>self.stream, \
324
('vvvv[log from %s]' % test.id()).ljust(78,'-')
150
325
print >>self.stream, test._get_log()
326
print >>self.stream, \
327
('^^^^[log from %s]' % test.id()).ljust(78,'-')
151
328
self.stream.writeln(self.separator2)
152
329
self.stream.writeln("%s" % err)
155
class TextTestRunner(unittest.TextTestRunner):
332
class TextTestRunner(object):
156
333
stop_on_failure = False
342
self.stream = unittest._WritelnDecorator(stream)
343
self.descriptions = descriptions
344
self.verbosity = verbosity
345
self.keep_output = keep_output
347
self._bench_history = bench_history
158
349
def _makeResult(self):
159
result = _MyResult(self.stream, self.descriptions, self.verbosity)
160
if self.stop_on_failure:
161
result = EarlyStoppingTestResultAdapter(result)
350
result = _MyResult(self.stream,
354
bench_history=self._bench_history)
355
result.stop_early = self.stop_on_failure
359
"Run the given test case or test suite."
360
result = self._makeResult()
361
startTime = time.time()
362
if self.pb is not None:
363
self.pb.update('Running tests', 0, test.countTestCases())
365
stopTime = time.time()
366
timeTaken = stopTime - startTime
368
self.stream.writeln(result.separator2)
369
run = result.testsRun
370
self.stream.writeln("Ran %d test%s in %.3fs" %
371
(run, run != 1 and "s" or "", timeTaken))
372
self.stream.writeln()
373
if not result.wasSuccessful():
374
self.stream.write("FAILED (")
375
failed, errored = map(len, (result.failures, result.errors))
377
self.stream.write("failures=%d" % failed)
379
if failed: self.stream.write(", ")
380
self.stream.write("errors=%d" % errored)
381
self.stream.writeln(")")
383
self.stream.writeln("OK")
384
if self.pb is not None:
385
self.pb.update('Cleaning up', 0, 1)
386
# This is still a little bogus,
387
# but only a little. Folk not using our testrunner will
388
# have to delete their temp directories themselves.
389
test_root = TestCaseInTempDir.TEST_ROOT
390
if result.wasSuccessful() or not self.keep_output:
391
if test_root is not None:
392
# If LANG=C we probably have created some bogus paths
393
# which rmtree(unicode) will fail to delete
394
# so make sure we are using rmtree(str) to delete everything
395
# except on win32, where rmtree(str) will fail
396
# since it doesn't have the property of byte-stream paths
397
# (they are either ascii or mbcs)
398
if sys.platform == 'win32':
399
# make sure we are using the unicode win32 api
400
test_root = unicode(test_root)
402
test_root = test_root.encode(
403
sys.getfilesystemencoding())
404
osutils.rmtree(test_root)
406
if self.pb is not None:
407
self.pb.note("Failed tests working directories are in '%s'\n",
411
"Failed tests working directories are in '%s'\n" %
413
TestCaseInTempDir.TEST_ROOT = None
414
if self.pb is not None:
248
550
raise AssertionError('pattern "%s" not found in "%s"'
249
551
% (needle_re, haystack))
553
def assertNotContainsRe(self, haystack, needle_re):
554
"""Assert that a does not match a regular expression"""
555
if re.search(needle_re, haystack):
556
raise AssertionError('pattern "%s" found in "%s"'
557
% (needle_re, haystack))
559
def assertSubset(self, sublist, superlist):
560
"""Assert that every entry in sublist is present in superlist."""
562
for entry in sublist:
563
if entry not in superlist:
564
missing.append(entry)
566
raise AssertionError("value(s) %r not present in container %r" %
567
(missing, superlist))
569
def assertIs(self, left, right):
570
if not (left is right):
571
raise AssertionError("%r is not %r." % (left, right))
573
def assertTransportMode(self, transport, path, mode):
574
"""Fail if a path does not have mode mode.
576
If modes are not supported on this transport, the assertion is ignored.
578
if not transport._can_roundtrip_unix_modebits():
580
path_stat = transport.stat(path)
581
actual_mode = stat.S_IMODE(path_stat.st_mode)
582
self.assertEqual(mode, actual_mode,
583
'mode of %r incorrect (%o != %o)' % (path, mode, actual_mode))
585
def assertIsInstance(self, obj, kls):
586
"""Fail if obj is not an instance of kls"""
587
if not isinstance(obj, kls):
588
self.fail("%r is an instance of %s rather than %s" % (
589
obj, obj.__class__, kls))
591
def _capture_warnings(self, a_callable, *args, **kwargs):
592
"""A helper for callDeprecated and applyDeprecated.
594
:param a_callable: A callable to call.
595
:param args: The positional arguments for the callable
596
:param kwargs: The keyword arguments for the callable
597
:return: A tuple (warnings, result). result is the result of calling
598
a_callable(*args, **kwargs).
601
def capture_warnings(msg, cls, stacklevel=None):
602
# we've hooked into a deprecation specific callpath,
603
# only deprecations should getting sent via it.
604
self.assertEqual(cls, DeprecationWarning)
605
local_warnings.append(msg)
606
original_warning_method = symbol_versioning.warn
607
symbol_versioning.set_warning_method(capture_warnings)
609
result = a_callable(*args, **kwargs)
611
symbol_versioning.set_warning_method(original_warning_method)
612
return (local_warnings, result)
614
def applyDeprecated(self, deprecation_format, a_callable, *args, **kwargs):
615
"""Call a deprecated callable without warning the user.
617
:param deprecation_format: The deprecation format that the callable
618
should have been deprecated with. This is the same type as the
619
parameter to deprecated_method/deprecated_function. If the
620
callable is not deprecated with this format, an assertion error
622
:param a_callable: A callable to call. This may be a bound method or
623
a regular function. It will be called with *args and **kwargs.
624
:param args: The positional arguments for the callable
625
:param kwargs: The keyword arguments for the callable
626
:return: The result of a_callable(*args, **kwargs)
628
call_warnings, result = self._capture_warnings(a_callable,
630
expected_first_warning = symbol_versioning.deprecation_string(
631
a_callable, deprecation_format)
632
if len(call_warnings) == 0:
633
self.fail("No assertion generated by call to %s" %
635
self.assertEqual(expected_first_warning, call_warnings[0])
638
def callDeprecated(self, expected, callable, *args, **kwargs):
639
"""Assert that a callable is deprecated in a particular way.
641
This is a very precise test for unusual requirements. The
642
applyDeprecated helper function is probably more suited for most tests
643
as it allows you to simply specify the deprecation format being used
644
and will ensure that that is issued for the function being called.
646
:param expected: a list of the deprecation warnings expected, in order
647
:param callable: The callable to call
648
:param args: The positional arguments for the callable
649
:param kwargs: The keyword arguments for the callable
651
call_warnings, result = self._capture_warnings(callable,
653
self.assertEqual(expected, call_warnings)
251
656
def _startLogFile(self):
252
657
"""Send bzr and test log messages to a temporary file.
254
659
The file is removed as the test is torn down.
256
661
fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
257
encoder, decoder, stream_reader, stream_writer = codecs.lookup('UTF-8')
258
self._log_file = stream_writer(os.fdopen(fileno, 'w+'))
259
bzrlib.trace.enable_test_log(self._log_file)
662
self._log_file = os.fdopen(fileno, 'w+')
663
self._log_nonce = bzrlib.trace.enable_test_log(self._log_file)
260
664
self._log_file_name = name
261
665
self.addCleanup(self._finishLogFile)
263
667
def _finishLogFile(self):
264
668
"""Finished with the log file.
266
Read contents into memory, close, and delete.
670
Close the file and delete it, unless setKeepLogfile was called.
268
bzrlib.trace.disable_test_log()
269
self._log_file.seek(0)
270
self._log_contents = self._log_file.read()
672
if self._log_file is None:
674
bzrlib.trace.disable_test_log(self._log_nonce)
271
675
self._log_file.close()
272
os.remove(self._log_file_name)
273
self._log_file = self._log_file_name = None
676
self._log_file = None
677
if not self._keep_log_file:
678
os.remove(self._log_file_name)
679
self._log_file_name = None
681
def setKeepLogfile(self):
682
"""Make the logfile not be deleted when _finishLogFile is called."""
683
self._keep_log_file = True
275
685
def addCleanup(self, callable):
276
686
"""Arrange to run a callable when this case is torn down.
288
698
'HOME': os.getcwd(),
289
699
'APPDATA': os.getcwd(),
701
'BZREMAIL': None, # may still be present in the environment
703
'BZR_PROGRESS_BAR': None,
293
705
self.__old_env = {}
294
706
self.addCleanup(self._restoreEnvironment)
295
707
for name, value in new_env.iteritems():
296
708
self._captureVar(name, value)
299
710
def _captureVar(self, name, newvalue):
300
"""Set an environment variable, preparing it to be reset when finished."""
301
self.__old_env[name] = os.environ.get(name, None)
303
if name in os.environ:
306
os.environ[name] = newvalue
309
def _restoreVar(name, value):
311
if name in os.environ:
314
os.environ[name] = value
711
"""Set an environment variable, and reset it when finished."""
712
self.__old_env[name] = osutils.set_or_unset_env(name, newvalue)
316
714
def _restoreEnvironment(self):
317
715
for name, value in self.__old_env.iteritems():
318
self._restoreVar(name, value)
716
osutils.set_or_unset_env(name, value)
320
718
def tearDown(self):
321
719
self._runCleanups()
322
720
unittest.TestCase.tearDown(self)
722
def time(self, callable, *args, **kwargs):
723
"""Run callable and accrue the time it takes to the benchmark time.
725
If lsprofiling is enabled (i.e. by --lsprof-time to bzr selftest) then
726
this will cause lsprofile statistics to be gathered and stored in
729
if self._benchtime is None:
733
if not self._gather_lsprof_in_benchmarks:
734
return callable(*args, **kwargs)
736
# record this benchmark
737
ret, stats = bzrlib.lsprof.profile(callable, *args, **kwargs)
739
self._benchcalls.append(((callable, args, kwargs), stats))
742
self._benchtime += time.time() - start
324
744
def _runCleanups(self):
325
745
"""Run registered cleanup functions.
327
747
This should only be called from TestCase.tearDown.
749
# TODO: Perhaps this should keep running cleanups even if
329
751
for cleanup_fn in reversed(self._cleanups):
332
754
def log(self, *args):
336
"""Return as a string the log for this test"""
337
if self._log_file_name:
338
return open(self._log_file_name).read()
757
def _get_log(self, keep_log_file=False):
758
"""Return as a string the log for this test. If the file is still
759
on disk and keep_log_file=False, delete the log file and store the
760
content in self._log_contents."""
761
# flush the log file, to get all content
763
bzrlib.trace._trace_file.flush()
764
if self._log_contents:
340
765
return self._log_contents
341
# TODO: Delete the log after it's been read in
766
if self._log_file_name is not None:
767
logfile = open(self._log_file_name)
769
log_contents = logfile.read()
772
if not keep_log_file:
773
self._log_contents = log_contents
774
os.remove(self._log_file_name)
777
return "DELETED log file to reduce memory footprint"
343
779
def capture(self, cmd, retcode=0):
344
780
"""Shortcut that splits cmd into words, runs, and returns stdout"""
345
781
return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
347
def run_bzr_captured(self, argv, retcode=0):
783
def run_bzr_captured(self, argv, retcode=0, encoding=None, stdin=None):
348
784
"""Invoke bzr and return (stdout, stderr).
350
786
Useful for code that wants to check the contents of the
399
850
This sends the stdout/stderr results into the test's log,
400
851
where it may be useful for debugging. See also run_captured.
853
:param stdin: A string to be used as stdin for the command.
402
855
retcode = kwargs.pop('retcode', 0)
403
return self.run_bzr_captured(args, retcode)
856
encoding = kwargs.pop('encoding', None)
857
stdin = kwargs.pop('stdin', None)
858
return self.run_bzr_captured(args, retcode=retcode, encoding=encoding, stdin=stdin)
860
def run_bzr_decode(self, *args, **kwargs):
861
if 'encoding' in kwargs:
862
encoding = kwargs['encoding']
864
encoding = bzrlib.user_encoding
865
return self.run_bzr(*args, **kwargs)[0].decode(encoding)
867
def run_bzr_error(self, error_regexes, *args, **kwargs):
868
"""Run bzr, and check that stderr contains the supplied regexes
870
:param error_regexes: Sequence of regular expressions which
871
must each be found in the error output. The relative ordering
873
:param args: command-line arguments for bzr
874
:param kwargs: Keyword arguments which are interpreted by run_bzr
875
This function changes the default value of retcode to be 3,
876
since in most cases this is run when you expect bzr to fail.
877
:return: (out, err) The actual output of running the command (in case you
878
want to do more inspection)
881
# Make sure that commit is failing because there is nothing to do
882
self.run_bzr_error(['no changes to commit'],
883
'commit', '-m', 'my commit comment')
884
# Make sure --strict is handling an unknown file, rather than
885
# giving us the 'nothing to do' error
886
self.build_tree(['unknown'])
887
self.run_bzr_error(['Commit refused because there are unknown files'],
888
'commit', '--strict', '-m', 'my commit comment')
890
kwargs.setdefault('retcode', 3)
891
out, err = self.run_bzr(*args, **kwargs)
892
for regex in error_regexes:
893
self.assertContainsRe(err, regex)
896
def run_bzr_subprocess(self, *args, **kwargs):
897
"""Run bzr in a subprocess for testing.
899
This starts a new Python interpreter and runs bzr in there.
900
This should only be used for tests that have a justifiable need for
901
this isolation: e.g. they are testing startup time, or signal
902
handling, or early startup code, etc. Subprocess code can't be
903
profiled or debugged so easily.
905
:param retcode: The status code that is expected. Defaults to 0. If
906
None is supplied, the status code is not checked.
907
:param env_changes: A dictionary which lists changes to environment
908
variables. A value of None will unset the env variable.
909
The values must be strings. The change will only occur in the
910
child, so you don't need to fix the environment after running.
911
:param universal_newlines: Convert CRLF => LF
913
env_changes = kwargs.get('env_changes', {})
914
process = self.start_bzr_subprocess(args, env_changes=env_changes)
915
# We distinguish between retcode=None and retcode not passed.
916
supplied_retcode = kwargs.get('retcode', 0)
917
return self.finish_bzr_subprocess(process, retcode=supplied_retcode,
918
universal_newlines=kwargs.get('universal_newlines', False),
921
def start_bzr_subprocess(self, process_args, env_changes=None,
922
skip_if_plan_to_signal=False):
923
"""Start bzr in a subprocess for testing.
925
This starts a new Python interpreter and runs bzr in there.
926
This should only be used for tests that have a justifiable need for
927
this isolation: e.g. they are testing startup time, or signal
928
handling, or early startup code, etc. Subprocess code can't be
929
profiled or debugged so easily.
931
:param process_args: a list of arguments to pass to the bzr executable,
932
for example `['--version']`.
933
:param env_changes: A dictionary which lists changes to environment
934
variables. A value of None will unset the env variable.
935
The values must be strings. The change will only occur in the
936
child, so you don't need to fix the environment after running.
937
:param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
940
:returns: Popen object for the started process.
942
if skip_if_plan_to_signal:
943
if not getattr(os, 'kill', None):
944
raise TestSkipped("os.kill not available.")
946
if env_changes is None:
950
def cleanup_environment():
951
for env_var, value in env_changes.iteritems():
952
old_env[env_var] = osutils.set_or_unset_env(env_var, value)
954
def restore_environment():
955
for env_var, value in old_env.iteritems():
956
osutils.set_or_unset_env(env_var, value)
958
bzr_path = self.get_bzr_path()
961
# win32 subprocess doesn't support preexec_fn
962
# so we will avoid using it on all platforms, just to
963
# make sure the code path is used, and we don't break on win32
964
cleanup_environment()
965
process = Popen([sys.executable, bzr_path] + list(process_args),
966
stdin=PIPE, stdout=PIPE, stderr=PIPE)
968
restore_environment()
971
def get_bzr_path(self):
972
"""Return the path of the 'bzr' executable for this test suite."""
973
bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
974
if not os.path.isfile(bzr_path):
975
# We are probably installed. Assume sys.argv is the right file
976
bzr_path = sys.argv[0]
979
def finish_bzr_subprocess(self, process, retcode=0, send_signal=None,
980
universal_newlines=False, process_args=None):
981
"""Finish the execution of process.
983
:param process: the Popen object returned from start_bzr_subprocess.
984
:param retcode: The status code that is expected. Defaults to 0. If
985
None is supplied, the status code is not checked.
986
:param send_signal: an optional signal to send to the process.
987
:param universal_newlines: Convert CRLF => LF
988
:returns: (stdout, stderr)
990
if send_signal is not None:
991
os.kill(process.pid, send_signal)
992
out, err = process.communicate()
994
if universal_newlines:
995
out = out.replace('\r\n', '\n')
996
err = err.replace('\r\n', '\n')
998
if retcode is not None and retcode != process.returncode:
999
if process_args is None:
1000
process_args = "(unknown args)"
1001
mutter('Output of bzr %s:\n%s', process_args, out)
1002
mutter('Error for bzr %s:\n%s', process_args, err)
1003
self.fail('Command bzr %s failed with retcode %s != %s'
1004
% (process_args, retcode, process.returncode))
405
1007
def check_inventory_shape(self, inv, shape):
406
1008
"""Compare an inventory to a list of expected names.
500
1119
# successfully created
501
TestCaseInTempDir.TEST_ROOT = os.path.abspath(root)
1120
TestCaseInTempDir.TEST_ROOT = osutils.abspath(root)
503
1122
# make a fake bzr directory there to prevent any tests propagating
504
1123
# up onto the source directory's real branch
505
os.mkdir(os.path.join(TestCaseInTempDir.TEST_ROOT, '.bzr'))
1124
bzrdir.BzrDir.create_standalone_workingtree(TestCaseInTempDir.TEST_ROOT)
507
1126
def setUp(self):
508
1127
super(TestCaseInTempDir, self).setUp()
509
1128
self._make_test_root()
510
1129
_currentdir = os.getcwdu()
1130
# shorten the name, to avoid test failures due to path length
511
1131
short_id = self.id().replace('bzrlib.tests.', '') \
512
.replace('__main__.', '')
513
self.test_dir = os.path.join(self.TEST_ROOT, short_id)
514
os.mkdir(self.test_dir)
515
os.chdir(self.test_dir)
516
os.environ['HOME'] = self.test_dir
1132
.replace('__main__.', '')[-100:]
1133
# it's possible the same test class is run several times for
1134
# parameterized tests, so make sure the names don't collide.
1138
candidate_dir = '%s/%s.%d' % (self.TEST_ROOT, short_id, i)
1140
candidate_dir = '%s/%s' % (self.TEST_ROOT, short_id)
1141
if os.path.exists(candidate_dir):
1145
os.mkdir(candidate_dir)
1146
self.test_home_dir = candidate_dir + '/home'
1147
os.mkdir(self.test_home_dir)
1148
self.test_dir = candidate_dir + '/work'
1149
os.mkdir(self.test_dir)
1150
os.chdir(self.test_dir)
1152
os.environ['HOME'] = self.test_home_dir
1153
os.environ['APPDATA'] = self.test_home_dir
517
1154
def _leaveDirectory():
518
1155
os.chdir(_currentdir)
519
1156
self.addCleanup(_leaveDirectory)
521
def build_tree(self, shape, line_endings='native'):
1158
def build_tree(self, shape, line_endings='native', transport=None):
522
1159
"""Build a test tree according to a pattern.
524
1161
shape is a sequence of file specifications. If the final
525
1162
character is '/', a directory is created.
1164
This assumes that all the elements in the tree being built are new.
527
1166
This doesn't add anything to a branch.
528
1167
:param line_endings: Either 'binary' or 'native'
529
1168
in binary mode, exact contents are written
530
1169
in native mode, the line endings match the
531
1170
default platform endings.
1172
:param transport: A transport to write to, for building trees on
1173
VFS's. If the transport is readonly or None,
1174
"." is opened automatically.
533
# XXX: It's OK to just create them using forward slashes on windows?
1176
# It's OK to just create them using forward slashes on windows.
1177
if transport is None or transport.is_readonly():
1178
transport = get_transport(".")
534
1179
for name in shape:
535
1180
self.assert_(isinstance(name, basestring))
536
1181
if name[-1] == '/':
1182
transport.mkdir(urlutils.escape(name[:-1]))
539
1184
if line_endings == 'binary':
541
1186
elif line_endings == 'native':
544
raise BzrError('Invalid line ending request %r' % (line_endings,))
545
print >>f, "contents of", name
1189
raise errors.BzrError('Invalid line ending request %r' % (line_endings,))
1190
content = "contents of %s%s" % (name.encode('utf-8'), end)
1191
# Technically 'put()' is the right command. However, put
1192
# uses an AtomicFile, which requires an extra rename into place
1193
# As long as the files didn't exist in the past, append() will
1194
# do the same thing as put()
1195
# On jam's machine, make_kernel_like_tree is:
1196
# put: 4.5-7.5s (averaging 6s)
1198
# put_non_atomic: 2.9-4.5s
1199
transport.put_bytes_non_atomic(urlutils.escape(name), content)
548
1201
def build_tree_contents(self, shape):
549
1202
build_tree_contents(shape)
551
1204
def failUnlessExists(self, path):
552
1205
"""Fail unless path, which may be abs or relative, exists."""
553
self.failUnless(bzrlib.osutils.lexists(path))
1206
self.failUnless(osutils.lexists(path))
1208
def failIfExists(self, path):
1209
"""Fail if path, which may be abs or relative, exists."""
1210
self.failIf(osutils.lexists(path))
555
1212
def assertFileEqual(self, content, path):
556
1213
"""Fail if path does not contain 'content'."""
557
self.failUnless(bzrlib.osutils.lexists(path))
1214
self.failUnless(osutils.lexists(path))
1215
# TODO: jam 20060427 Shouldn't this be 'rb'?
558
1216
self.assertEqualDiff(content, open(path, 'r').read())
1219
class TestCaseWithTransport(TestCaseInTempDir):
1220
"""A test case that provides get_url and get_readonly_url facilities.
1222
These back onto two transport servers, one for readonly access and one for
1225
If no explicit class is provided for readonly access, a
1226
ReadonlyTransportDecorator is used instead which allows the use of non disk
1227
based read write transports.
1229
If an explicit class is provided for readonly access, that server and the
1230
readwrite one must both define get_url() as resolving to os.getcwd().
1233
def __init__(self, methodName='testMethod'):
1234
super(TestCaseWithTransport, self).__init__(methodName)
1235
self.__readonly_server = None
1236
self.__server = None
1237
self.transport_server = default_transport
1238
self.transport_readonly_server = None
1240
def get_readonly_url(self, relpath=None):
1241
"""Get a URL for the readonly transport.
1243
This will either be backed by '.' or a decorator to the transport
1244
used by self.get_url()
1245
relpath provides for clients to get a path relative to the base url.
1246
These should only be downwards relative, not upwards.
1248
base = self.get_readonly_server().get_url()
1249
if relpath is not None:
1250
if not base.endswith('/'):
1252
base = base + relpath
1255
def get_readonly_server(self):
1256
"""Get the server instance for the readonly transport
1258
This is useful for some tests with specific servers to do diagnostics.
1260
if self.__readonly_server is None:
1261
if self.transport_readonly_server is None:
1262
# readonly decorator requested
1263
# bring up the server
1265
self.__readonly_server = ReadonlyServer()
1266
self.__readonly_server.setUp(self.__server)
1268
self.__readonly_server = self.transport_readonly_server()
1269
self.__readonly_server.setUp()
1270
self.addCleanup(self.__readonly_server.tearDown)
1271
return self.__readonly_server
1273
def get_server(self):
1274
"""Get the read/write server instance.
1276
This is useful for some tests with specific servers that need
1279
if self.__server is None:
1280
self.__server = self.transport_server()
1281
self.__server.setUp()
1282
self.addCleanup(self.__server.tearDown)
1283
return self.__server
1285
def get_url(self, relpath=None):
1286
"""Get a URL (or maybe a path) for the readwrite transport.
1288
This will either be backed by '.' or to an equivalent non-file based
1290
relpath provides for clients to get a path relative to the base url.
1291
These should only be downwards relative, not upwards.
1293
base = self.get_server().get_url()
1294
if relpath is not None and relpath != '.':
1295
if not base.endswith('/'):
1297
# XXX: Really base should be a url; we did after all call
1298
# get_url()! But sometimes it's just a path (from
1299
# LocalAbspathServer), and it'd be wrong to append urlescaped data
1300
# to a non-escaped local path.
1301
if base.startswith('./') or base.startswith('/'):
1304
base += urlutils.escape(relpath)
1307
def get_transport(self):
1308
"""Return a writeable transport for the test scratch space"""
1309
t = get_transport(self.get_url())
1310
self.assertFalse(t.is_readonly())
1313
def get_readonly_transport(self):
1314
"""Return a readonly transport for the test scratch space
1316
This can be used to test that operations which should only need
1317
readonly access in fact do not try to write.
1319
t = get_transport(self.get_readonly_url())
1320
self.assertTrue(t.is_readonly())
1323
def make_branch(self, relpath, format=None):
1324
"""Create a branch on the transport at relpath."""
1325
repo = self.make_repository(relpath, format=format)
1326
return repo.bzrdir.create_branch()
1328
def make_bzrdir(self, relpath, format=None):
1330
# might be a relative or absolute path
1331
maybe_a_url = self.get_url(relpath)
1332
segments = maybe_a_url.rsplit('/', 1)
1333
t = get_transport(maybe_a_url)
1334
if len(segments) > 1 and segments[-1] not in ('', '.'):
1337
except errors.FileExists:
1340
format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
1341
return format.initialize_on_transport(t)
1342
except errors.UninitializableFormat:
1343
raise TestSkipped("Format %s is not initializable." % format)
1345
def make_repository(self, relpath, shared=False, format=None):
1346
"""Create a repository on our default transport at relpath."""
1347
made_control = self.make_bzrdir(relpath, format=format)
1348
return made_control.create_repository(shared=shared)
1350
def make_branch_and_memory_tree(self, relpath):
1351
"""Create a branch on the default transport and a MemoryTree for it."""
1352
b = self.make_branch(relpath)
1353
return memorytree.MemoryTree.create_on_branch(b)
1355
def make_branch_and_tree(self, relpath, format=None):
1356
"""Create a branch on the transport and a tree locally.
1358
If the transport is not a LocalTransport, the Tree can't be created on
1359
the transport. In that case the working tree is created in the local
1360
directory, and the returned tree's branch and repository will also be
1363
This will fail if the original default transport for this test
1364
case wasn't backed by the working directory, as the branch won't
1365
be on disk for us to open it.
1367
:param format: The BzrDirFormat.
1368
:returns: the WorkingTree.
1370
# TODO: always use the local disk path for the working tree,
1371
# this obviously requires a format that supports branch references
1372
# so check for that by checking bzrdir.BzrDirFormat.get_default_format()
1374
b = self.make_branch(relpath, format=format)
1376
return b.bzrdir.create_workingtree()
1377
except errors.NotLocalUrl:
1378
# We can only make working trees locally at the moment. If the
1379
# transport can't support them, then reopen the branch on a local
1380
# transport, and create the working tree there.
1382
# Possibly we should instead keep
1383
# the non-disk-backed branch and create a local checkout?
1384
bd = bzrdir.BzrDir.open(relpath)
1385
return bd.create_workingtree()
1387
def assertIsDirectory(self, relpath, transport):
1388
"""Assert that relpath within transport is a directory.
1390
This may not be possible on all transports; in that case it propagates
1391
a TransportNotPossible.
1394
mode = transport.stat(relpath).st_mode
1395
except errors.NoSuchFile:
1396
self.fail("path %s is not a directory; no such file"
1398
if not stat.S_ISDIR(mode):
1399
self.fail("path %s is not a directory; has mode %#o"
1403
class ChrootedTestCase(TestCaseWithTransport):
1404
"""A support class that provides readonly urls outside the local namespace.
1406
This is done by checking if self.transport_server is a MemoryServer. if it
1407
is then we are chrooted already, if it is not then an HttpServer is used
1410
TODO RBC 20060127: make this an option to TestCaseWithTransport so it can
1411
be used without needed to redo it when a different
1412
subclass is in use ?
1416
super(ChrootedTestCase, self).setUp()
1417
if not self.transport_server == bzrlib.transport.memory.MemoryServer:
1418
self.transport_readonly_server = bzrlib.transport.http.HttpServer
561
1421
def filter_suite_by_re(suite, pattern):
1422
result = TestUtil.TestSuite()
563
1423
filter_re = re.compile(pattern)
564
1424
for test in iter_suite_tests(suite):
565
1425
if filter_re.search(test.id()):
570
1430
def run_suite(suite, name='test', verbose=False, pattern=".*",
571
stop_on_failure=False, keep_output=False):
1431
stop_on_failure=False, keep_output=False,
1432
transport=None, lsprof_timed=None, bench_history=None):
572
1433
TestCaseInTempDir._TEST_NAME = name
1434
TestCase._gather_lsprof_in_benchmarks = lsprof_timed
1440
pb = progress.ProgressBar()
577
1441
runner = TextTestRunner(stream=sys.stdout,
1443
verbosity=verbosity,
1444
keep_output=keep_output,
1446
bench_history=bench_history)
580
1447
runner.stop_on_failure=stop_on_failure
581
1448
if pattern != '.*':
582
1449
suite = filter_suite_by_re(suite, pattern)
583
1450
result = runner.run(suite)
584
# This is still a little bogus,
585
# but only a little. Folk not using our testrunner will
586
# have to delete their temp directories themselves.
587
if result.wasSuccessful() or not keep_output:
588
if TestCaseInTempDir.TEST_ROOT is not None:
589
shutil.rmtree(TestCaseInTempDir.TEST_ROOT)
591
print "Failed tests working directories are in '%s'\n" % TestCaseInTempDir.TEST_ROOT
592
1451
return result.wasSuccessful()
595
1454
def selftest(verbose=False, pattern=".*", stop_on_failure=True,
1457
test_suite_factory=None,
1459
bench_history=None):
597
1460
"""Run the whole test suite under the enhanced runner"""
598
return run_suite(test_suite(), 'testbzr', verbose=verbose, pattern=pattern,
599
stop_on_failure=stop_on_failure, keep_output=keep_output)
1461
# XXX: Very ugly way to do this...
1462
# Disable warning about old formats because we don't want it to disturb
1463
# any blackbox tests.
1464
from bzrlib import repository
1465
repository._deprecation_warning_done = True
1467
global default_transport
1468
if transport is None:
1469
transport = default_transport
1470
old_transport = default_transport
1471
default_transport = transport
1473
if test_suite_factory is None:
1474
suite = test_suite()
1476
suite = test_suite_factory()
1477
return run_suite(suite, 'testbzr', verbose=verbose, pattern=pattern,
1478
stop_on_failure=stop_on_failure, keep_output=keep_output,
1479
transport=transport,
1480
lsprof_timed=lsprof_timed,
1481
bench_history=bench_history)
1483
default_transport = old_transport
602
1486
def test_suite():
603
"""Build and return TestSuite for the whole program."""
604
from doctest import DocTestSuite
606
global MODULES_TO_DOCTEST
1487
"""Build and return TestSuite for the whole of bzrlib.
1489
This function can be replaced if you need to change the default test
1490
suite on a global basis, but it is not encouraged.
1493
'bzrlib.tests.test_ancestry',
609
1494
'bzrlib.tests.test_api',
610
'bzrlib.tests.test_gpg',
611
'bzrlib.tests.test_identitymap',
612
'bzrlib.tests.test_inv',
613
'bzrlib.tests.test_ancestry',
1495
'bzrlib.tests.test_atomicfile',
1496
'bzrlib.tests.test_bad_files',
1497
'bzrlib.tests.test_branch',
1498
'bzrlib.tests.test_bundle',
1499
'bzrlib.tests.test_bzrdir',
1500
'bzrlib.tests.test_cache_utf8',
1501
'bzrlib.tests.test_command',
614
1502
'bzrlib.tests.test_commit',
615
'bzrlib.tests.test_command',
616
1503
'bzrlib.tests.test_commit_merge',
617
1504
'bzrlib.tests.test_config',
618
'bzrlib.tests.test_merge3',
619
'bzrlib.tests.test_merge',
1505
'bzrlib.tests.test_conflicts',
1506
'bzrlib.tests.test_decorators',
1507
'bzrlib.tests.test_diff',
1508
'bzrlib.tests.test_doc_generate',
1509
'bzrlib.tests.test_errors',
1510
'bzrlib.tests.test_escaped_store',
1511
'bzrlib.tests.test_fetch',
1512
'bzrlib.tests.test_ftp_transport',
1513
'bzrlib.tests.test_gpg',
1514
'bzrlib.tests.test_graph',
620
1515
'bzrlib.tests.test_hashcache',
621
'bzrlib.tests.test_status',
1516
'bzrlib.tests.test_http',
1517
'bzrlib.tests.test_http_response',
1518
'bzrlib.tests.test_identitymap',
1519
'bzrlib.tests.test_ignores',
1520
'bzrlib.tests.test_inv',
1521
'bzrlib.tests.test_knit',
1522
'bzrlib.tests.test_lazy_import',
1523
'bzrlib.tests.test_lockdir',
1524
'bzrlib.tests.test_lockable_files',
622
1525
'bzrlib.tests.test_log',
1526
'bzrlib.tests.test_memorytree',
1527
'bzrlib.tests.test_merge',
1528
'bzrlib.tests.test_merge3',
1529
'bzrlib.tests.test_merge_core',
1530
'bzrlib.tests.test_missing',
1531
'bzrlib.tests.test_msgeditor',
1532
'bzrlib.tests.test_nonascii',
1533
'bzrlib.tests.test_options',
1534
'bzrlib.tests.test_osutils',
1535
'bzrlib.tests.test_patch',
1536
'bzrlib.tests.test_patches',
1537
'bzrlib.tests.test_permissions',
1538
'bzrlib.tests.test_plugins',
1539
'bzrlib.tests.test_progress',
1540
'bzrlib.tests.test_reconcile',
1541
'bzrlib.tests.test_repository',
1542
'bzrlib.tests.test_revert',
1543
'bzrlib.tests.test_revision',
623
1544
'bzrlib.tests.test_revisionnamespaces',
624
'bzrlib.tests.test_branch',
625
'bzrlib.tests.test_revision',
626
'bzrlib.tests.test_revision_info',
627
'bzrlib.tests.test_merge_core',
1545
'bzrlib.tests.test_revisiontree',
1546
'bzrlib.tests.test_rio',
1547
'bzrlib.tests.test_sampler',
1548
'bzrlib.tests.test_selftest',
1549
'bzrlib.tests.test_setup',
1550
'bzrlib.tests.test_sftp_transport',
628
1551
'bzrlib.tests.test_smart_add',
629
'bzrlib.tests.test_bad_files',
630
'bzrlib.tests.test_diff',
631
'bzrlib.tests.test_parent',
632
'bzrlib.tests.test_xml',
633
'bzrlib.tests.test_weave',
634
'bzrlib.tests.test_fetch',
635
'bzrlib.tests.test_whitebox',
1552
'bzrlib.tests.test_smart_transport',
1553
'bzrlib.tests.test_source',
1554
'bzrlib.tests.test_status',
636
1555
'bzrlib.tests.test_store',
637
'bzrlib.tests.test_sampler',
1556
'bzrlib.tests.test_symbol_versioning',
1557
'bzrlib.tests.test_testament',
1558
'bzrlib.tests.test_textfile',
1559
'bzrlib.tests.test_textmerge',
1560
'bzrlib.tests.test_trace',
638
1561
'bzrlib.tests.test_transactions',
1562
'bzrlib.tests.test_transform',
639
1563
'bzrlib.tests.test_transport',
640
'bzrlib.tests.test_sftp',
641
'bzrlib.tests.test_graph',
1564
'bzrlib.tests.test_tree',
1565
'bzrlib.tests.test_treebuilder',
1566
'bzrlib.tests.test_tsort',
1567
'bzrlib.tests.test_tuned_gzip',
1568
'bzrlib.tests.test_ui',
1569
'bzrlib.tests.test_upgrade',
1570
'bzrlib.tests.test_urlutils',
1571
'bzrlib.tests.test_versionedfile',
1572
'bzrlib.tests.test_version',
1573
'bzrlib.tests.test_weave',
1574
'bzrlib.tests.test_whitebox',
642
1575
'bzrlib.tests.test_workingtree',
643
'bzrlib.tests.test_upgrade',
644
'bzrlib.tests.test_uncommit',
645
'bzrlib.tests.test_ui',
646
'bzrlib.tests.test_conflicts',
647
'bzrlib.tests.test_testament',
648
'bzrlib.tests.test_annotate',
649
'bzrlib.tests.test_revprops',
650
'bzrlib.tests.test_options',
651
'bzrlib.tests.test_http',
652
'bzrlib.tests.test_nonascii',
653
'bzrlib.tests.test_plugins',
654
'bzrlib.tests.test_reweave',
655
'bzrlib.tests.test_tsort',
656
'bzrlib.tests.test_trace',
657
'bzrlib.tests.test_rio',
658
'bzrlib.tests.test_msgeditor',
659
'bzrlib.tests.test_selftest',
1576
'bzrlib.tests.test_xml',
662
print '%10s: %s' % ('bzr', os.path.realpath(sys.argv[0]))
663
print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
666
# python2.4's TestLoader.loadTestsFromNames gives very poor
667
# errors if it fails to load a named module - no indication of what's
668
# actually wrong, just "no such module". We should probably override that
669
# class, but for the moment just load them ourselves. (mbp 20051202)
670
loader = TestLoader()
671
for mod_name in testmod_names:
672
mod = _load_module_by_name(mod_name)
673
suite.addTest(loader.loadTestsFromModule(mod))
1578
test_transport_implementations = [
1579
'bzrlib.tests.test_transport_implementations',
1580
'bzrlib.tests.test_read_bundle',
1582
suite = TestUtil.TestSuite()
1583
loader = TestUtil.TestLoader()
1584
suite.addTest(loader.loadTestsFromModuleNames(testmod_names))
1585
from bzrlib.transport import TransportTestProviderAdapter
1586
adapter = TransportTestProviderAdapter()
1587
adapt_modules(test_transport_implementations, adapter, loader, suite)
674
1588
for package in packages_to_test():
675
1589
suite.addTest(package.test_suite())
676
1590
for m in MODULES_TO_TEST:
677
1591
suite.addTest(loader.loadTestsFromModule(m))
678
for m in (MODULES_TO_DOCTEST):
679
suite.addTest(DocTestSuite(m))
1592
for m in MODULES_TO_DOCTEST:
1593
suite.addTest(doctest.DocTestSuite(m))
680
1594
for name, plugin in bzrlib.plugin.all_plugins().items():
681
if hasattr(plugin, 'test_suite'):
1595
if getattr(plugin, 'test_suite', None) is not None:
682
1596
suite.addTest(plugin.test_suite())
686
def _load_module_by_name(mod_name):
687
parts = mod_name.split('.')
688
module = __import__(mod_name)
690
# for historical reasons python returns the top-level module even though
691
# it loads the submodule; we need to walk down to get the one we want.
693
module = getattr(module, parts.pop(0))
1600
def adapt_modules(mods_list, adapter, loader, suite):
1601
"""Adapt the modules in mods_list using adapter and add to suite."""
1602
for test in iter_suite_tests(loader.loadTestsFromModuleNames(mods_list)):
1603
suite.addTests(adapter.adapt(test))