1
# Copyright (C) 2005, 2006 by Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
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.
30
from cStringIO import StringIO
39
from subprocess import Popen, PIPE
46
from bzrlib import memorytree
48
import bzrlib.bzrdir as bzrdir
49
import bzrlib.commands
50
import bzrlib.bundle.serializer
51
import bzrlib.errors as errors
53
import bzrlib.inventory
54
import bzrlib.iterablefile
59
# lsprof not available
61
from bzrlib.merge import merge_inner
64
import bzrlib.osutils as osutils
66
import bzrlib.progress as progress
67
from bzrlib.revision import common_ancestor
69
from bzrlib import symbol_versioning
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
75
from bzrlib.trace import mutter
76
from bzrlib.tests import TestUtil
77
from bzrlib.tests.TestUtil import (
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
88
MODULES_TO_DOCTEST = [
90
bzrlib.bundle.serializer,
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.
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,
137
class _MyResult(unittest._TextTestResult):
138
"""Custom TestResult.
140
Shows output in a different format, including displaying runtime for tests.
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)
208
def startTest(self, test):
209
unittest.TestResult.startTest(self, test)
210
# In a short description, the important words are in
211
# the beginning, but in an id, the important words are
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)
231
self.stream.write(what)
232
elif self.dots and self.pb is not None:
233
self.pb.update(what, self.testsRun - 1, None)
235
self._recordTestStartTime()
237
def _recordTestStartTime(self):
238
"""Record that a test has started."""
239
self._start_time = time.time()
241
def addError(self, test, err):
242
if isinstance(err[1], TestSkipped):
243
return self.addSkipped(test, err)
244
unittest.TestResult.addError(self, test, err)
245
test.setKeepLogfile()
246
self.extractBenchmarkTime(test)
248
self.stream.writeln("ERROR %s" % self._testTimeString())
249
elif self.dots and self.pb is None:
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()))
260
def addFailure(self, test, err):
261
unittest.TestResult.addFailure(self, test, err)
262
test.setKeepLogfile()
263
self.extractBenchmarkTime(test)
265
self.stream.writeln(" FAIL %s" % self._testTimeString())
266
elif self.dots and self.pb is None:
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()))
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),
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:
290
self.stream.write('~')
292
self.pb.update(self._ellipsise_unimportant_words('OK', 13), self.testsRun, None)
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)
317
def printErrorList(self, flavour, errors):
318
for test, err in errors:
319
self.stream.writeln(self.separator1)
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,'-')
325
print >>self.stream, test._get_log()
326
print >>self.stream, \
327
('^^^^[log from %s]' % test.id()).ljust(78,'-')
328
self.stream.writeln(self.separator2)
329
self.stream.writeln("%s" % err)
332
class TextTestRunner(object):
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
349
def _makeResult(self):
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:
419
def iter_suite_tests(suite):
420
"""Return all tests in a suite, recursing through nested suites"""
421
for item in suite._tests:
422
if isinstance(item, unittest.TestCase):
424
elif isinstance(item, unittest.TestSuite):
425
for r in iter_suite_tests(item):
428
raise Exception('unknown object %r inside test suite %r'
432
class TestSkipped(Exception):
433
"""Indicates that a test was intentionally skipped, rather than failing."""
436
class CommandFailed(Exception):
440
class StringIOWrapper(object):
441
"""A wrapper around cStringIO which just adds an encoding attribute.
443
Internally we can check sys.stdout to see what the output encoding
444
should be. However, cStringIO has no encoding attribute that we can
445
set. So we wrap it instead.
450
def __init__(self, s=None):
452
self.__dict__['_cstring'] = StringIO(s)
454
self.__dict__['_cstring'] = StringIO()
456
def __getattr__(self, name, getattr=getattr):
457
return getattr(self.__dict__['_cstring'], name)
459
def __setattr__(self, name, val):
460
if name == 'encoding':
461
self.__dict__['encoding'] = val
463
return setattr(self._cstring, name, val)
466
class TestCase(unittest.TestCase):
467
"""Base class for bzr unit tests.
469
Tests that need access to disk resources should subclass
470
TestCaseInTempDir not TestCase.
472
Error and debug log messages are redirected from their usual
473
location into a temporary file, the contents of which can be
474
retrieved by _get_log(). We use a real OS file, not an in-memory object,
475
so that it can also capture file IO. When the test completes this file
476
is read into memory and removed from disk.
478
There are also convenience functions to invoke bzr's command-line
479
routine, and to build and check bzr trees.
481
In addition to the usual method of overriding tearDown(), this class also
482
allows subclasses to register functions into the _cleanups list, which is
483
run in order as the object is torn down. It's less likely this will be
484
accidentally overlooked.
487
_log_file_name = None
489
_keep_log_file = False
490
# record lsprof data when performing benchmark calls.
491
_gather_lsprof_in_benchmarks = False
493
def __init__(self, methodName='testMethod'):
494
super(TestCase, self).__init__(methodName)
498
unittest.TestCase.setUp(self)
499
self._cleanEnvironment()
500
bzrlib.trace.disable_default_logging()
502
self._benchcalls = []
503
self._benchtime = None
505
def _ndiff_strings(self, a, b):
506
"""Return ndiff between two strings containing lines.
508
A trailing newline is added if missing to make the strings
510
if b and b[-1] != '\n':
512
if a and a[-1] != '\n':
514
difflines = difflib.ndiff(a.splitlines(True),
516
linejunk=lambda x: False,
517
charjunk=lambda x: False)
518
return ''.join(difflines)
520
def assertEqualDiff(self, a, b, message=None):
521
"""Assert two texts are equal, if not raise an exception.
523
This is intended for use with multi-line strings where it can
524
be hard to find the differences by eye.
526
# TODO: perhaps override assertEquals to call this for strings?
530
message = "texts not equal:\n"
531
raise AssertionError(message +
532
self._ndiff_strings(a, b))
534
def assertEqualMode(self, mode, mode_test):
535
self.assertEqual(mode, mode_test,
536
'mode mismatch %o != %o' % (mode, mode_test))
538
def assertStartsWith(self, s, prefix):
539
if not s.startswith(prefix):
540
raise AssertionError('string %r does not start with %r' % (s, prefix))
542
def assertEndsWith(self, s, suffix):
543
"""Asserts that s ends with suffix."""
544
if not s.endswith(suffix):
545
raise AssertionError('string %r does not end with %r' % (s, suffix))
547
def assertContainsRe(self, haystack, needle_re):
548
"""Assert that a contains something matching a regular expression."""
549
if not re.search(needle_re, haystack):
550
raise AssertionError('pattern "%s" not found in "%s"'
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)
656
def _startLogFile(self):
657
"""Send bzr and test log messages to a temporary file.
659
The file is removed as the test is torn down.
661
fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
662
self._log_file = os.fdopen(fileno, 'w+')
663
self._log_nonce = bzrlib.trace.enable_test_log(self._log_file)
664
self._log_file_name = name
665
self.addCleanup(self._finishLogFile)
667
def _finishLogFile(self):
668
"""Finished with the log file.
670
Close the file and delete it, unless setKeepLogfile was called.
672
if self._log_file is None:
674
bzrlib.trace.disable_test_log(self._log_nonce)
675
self._log_file.close()
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
685
def addCleanup(self, callable):
686
"""Arrange to run a callable when this case is torn down.
688
Callables are run in the reverse of the order they are registered,
689
ie last-in first-out.
691
if callable in self._cleanups:
692
raise ValueError("cleanup function %r already registered on %s"
694
self._cleanups.append(callable)
696
def _cleanEnvironment(self):
699
'APPDATA': os.getcwd(),
701
'BZREMAIL': None, # may still be present in the environment
703
'BZR_PROGRESS_BAR': None,
706
self.addCleanup(self._restoreEnvironment)
707
for name, value in new_env.iteritems():
708
self._captureVar(name, value)
710
def _captureVar(self, name, newvalue):
711
"""Set an environment variable, and reset it when finished."""
712
self.__old_env[name] = osutils.set_or_unset_env(name, newvalue)
714
def _restoreEnvironment(self):
715
for name, value in self.__old_env.iteritems():
716
osutils.set_or_unset_env(name, value)
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
744
def _runCleanups(self):
745
"""Run registered cleanup functions.
747
This should only be called from TestCase.tearDown.
749
# TODO: Perhaps this should keep running cleanups even if
751
for cleanup_fn in reversed(self._cleanups):
754
def log(self, *args):
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:
765
return self._log_contents
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"
779
def capture(self, cmd, retcode=0):
780
"""Shortcut that splits cmd into words, runs, and returns stdout"""
781
return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
783
def run_bzr_captured(self, argv, retcode=0, encoding=None, stdin=None):
784
"""Invoke bzr and return (stdout, stderr).
786
Useful for code that wants to check the contents of the
787
output, the way error messages are presented, etc.
789
This should be the main method for tests that want to exercise the
790
overall behavior of the bzr application (rather than a unit test
791
or a functional test of the library.)
793
Much of the old code runs bzr by forking a new copy of Python, but
794
that is slower, harder to debug, and generally not necessary.
796
This runs bzr through the interface that catches and reports
797
errors, and with logging set to something approximating the
798
default, so that error reporting can be checked.
800
:param argv: arguments to invoke bzr
801
:param retcode: expected return code, or None for don't-care.
802
:param encoding: encoding for sys.stdout and sys.stderr
803
:param stdin: A string to be used as stdin for the command.
806
encoding = bzrlib.user_encoding
807
if stdin is not None:
808
stdin = StringIO(stdin)
809
stdout = StringIOWrapper()
810
stderr = StringIOWrapper()
811
stdout.encoding = encoding
812
stderr.encoding = encoding
814
self.log('run bzr: %r', argv)
815
# FIXME: don't call into logging here
816
handler = logging.StreamHandler(stderr)
817
handler.setLevel(logging.INFO)
818
logger = logging.getLogger('')
819
logger.addHandler(handler)
820
old_ui_factory = bzrlib.ui.ui_factory
821
bzrlib.ui.ui_factory = bzrlib.tests.blackbox.TestUIFactory(
824
bzrlib.ui.ui_factory.stdin = stdin
826
result = self.apply_redirected(stdin, stdout, stderr,
827
bzrlib.commands.run_bzr_catch_errors,
830
logger.removeHandler(handler)
831
bzrlib.ui.ui_factory = old_ui_factory
833
out = stdout.getvalue()
834
err = stderr.getvalue()
836
self.log('output:\n%r', out)
838
self.log('errors:\n%r', err)
839
if retcode is not None:
840
self.assertEquals(retcode, result)
843
def run_bzr(self, *args, **kwargs):
844
"""Invoke bzr, as if it were run from the command line.
846
This should be the main method for tests that want to exercise the
847
overall behavior of the bzr application (rather than a unit test
848
or a functional test of the library.)
850
This sends the stdout/stderr results into the test's log,
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.
855
retcode = kwargs.pop('retcode', 0)
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))
1007
def check_inventory_shape(self, inv, shape):
1008
"""Compare an inventory to a list of expected names.
1010
Fail if they are not precisely equal.
1013
shape = list(shape) # copy
1014
for path, ie in inv.entries():
1015
name = path.replace('\\', '/')
1016
if ie.kind == 'dir':
1023
self.fail("expected paths not found in inventory: %r" % shape)
1025
self.fail("unexpected paths found in inventory: %r" % extras)
1027
def apply_redirected(self, stdin=None, stdout=None, stderr=None,
1028
a_callable=None, *args, **kwargs):
1029
"""Call callable with redirected std io pipes.
1031
Returns the return code."""
1032
if not callable(a_callable):
1033
raise ValueError("a_callable must be callable.")
1035
stdin = StringIO("")
1037
if getattr(self, "_log_file", None) is not None:
1038
stdout = self._log_file
1042
if getattr(self, "_log_file", None is not None):
1043
stderr = self._log_file
1046
real_stdin = sys.stdin
1047
real_stdout = sys.stdout
1048
real_stderr = sys.stderr
1053
return a_callable(*args, **kwargs)
1055
sys.stdout = real_stdout
1056
sys.stderr = real_stderr
1057
sys.stdin = real_stdin
1059
@symbol_versioning.deprecated_method(symbol_versioning.zero_eleven)
1060
def merge(self, branch_from, wt_to):
1061
"""A helper for tests to do a ui-less merge.
1063
This should move to the main library when someone has time to integrate
1066
# minimal ui-less merge.
1067
wt_to.branch.fetch(branch_from)
1068
base_rev = common_ancestor(branch_from.last_revision(),
1069
wt_to.branch.last_revision(),
1070
wt_to.branch.repository)
1071
merge_inner(wt_to.branch, branch_from.basis_tree(),
1072
wt_to.branch.repository.revision_tree(base_rev),
1074
wt_to.add_parent_tree_id(branch_from.last_revision())
1077
BzrTestBase = TestCase
1080
class TestCaseInTempDir(TestCase):
1081
"""Derived class that runs a test within a temporary directory.
1083
This is useful for tests that need to create a branch, etc.
1085
The directory is created in a slightly complex way: for each
1086
Python invocation, a new temporary top-level directory is created.
1087
All test cases create their own directory within that. If the
1088
tests complete successfully, the directory is removed.
1090
InTempDir is an old alias for FunctionalTestCase.
1095
OVERRIDE_PYTHON = 'python'
1097
def check_file_contents(self, filename, expect):
1098
self.log("check contents of file %s" % filename)
1099
contents = file(filename, 'r').read()
1100
if contents != expect:
1101
self.log("expected: %r" % expect)
1102
self.log("actually: %r" % contents)
1103
self.fail("contents of %s not as expected" % filename)
1105
def _make_test_root(self):
1106
if TestCaseInTempDir.TEST_ROOT is not None:
1110
root = u'test%04d.tmp' % i
1114
if e.errno == errno.EEXIST:
1119
# successfully created
1120
TestCaseInTempDir.TEST_ROOT = osutils.abspath(root)
1122
# make a fake bzr directory there to prevent any tests propagating
1123
# up onto the source directory's real branch
1124
bzrdir.BzrDir.create_standalone_workingtree(TestCaseInTempDir.TEST_ROOT)
1127
super(TestCaseInTempDir, self).setUp()
1128
self._make_test_root()
1129
_currentdir = os.getcwdu()
1130
# shorten the name, to avoid test failures due to path length
1131
short_id = self.id().replace('bzrlib.tests.', '') \
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
1154
def _leaveDirectory():
1155
os.chdir(_currentdir)
1156
self.addCleanup(_leaveDirectory)
1158
def build_tree(self, shape, line_endings='native', transport=None):
1159
"""Build a test tree according to a pattern.
1161
shape is a sequence of file specifications. If the final
1162
character is '/', a directory is created.
1164
This assumes that all the elements in the tree being built are new.
1166
This doesn't add anything to a branch.
1167
:param line_endings: Either 'binary' or 'native'
1168
in binary mode, exact contents are written
1169
in native mode, the line endings match the
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.
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(".")
1180
self.assert_(isinstance(name, basestring))
1182
transport.mkdir(urlutils.escape(name[:-1]))
1184
if line_endings == 'binary':
1186
elif line_endings == 'native':
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)
1201
def build_tree_contents(self, shape):
1202
build_tree_contents(shape)
1204
def failUnlessExists(self, path):
1205
"""Fail unless path, which may be abs or relative, exists."""
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))
1212
def assertFileEqual(self, content, path):
1213
"""Fail if path does not contain 'content'."""
1214
self.failUnless(osutils.lexists(path))
1215
# TODO: jam 20060427 Shouldn't this be 'rb'?
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
1421
def filter_suite_by_re(suite, pattern):
1422
result = TestUtil.TestSuite()
1423
filter_re = re.compile(pattern)
1424
for test in iter_suite_tests(suite):
1425
if filter_re.search(test.id()):
1426
result.addTest(test)
1430
def run_suite(suite, name='test', verbose=False, pattern=".*",
1431
stop_on_failure=False, keep_output=False,
1432
transport=None, lsprof_timed=None, bench_history=None):
1433
TestCaseInTempDir._TEST_NAME = name
1434
TestCase._gather_lsprof_in_benchmarks = lsprof_timed
1440
pb = progress.ProgressBar()
1441
runner = TextTestRunner(stream=sys.stdout,
1443
verbosity=verbosity,
1444
keep_output=keep_output,
1446
bench_history=bench_history)
1447
runner.stop_on_failure=stop_on_failure
1449
suite = filter_suite_by_re(suite, pattern)
1450
result = runner.run(suite)
1451
return result.wasSuccessful()
1454
def selftest(verbose=False, pattern=".*", stop_on_failure=True,
1457
test_suite_factory=None,
1459
bench_history=None):
1460
"""Run the whole test suite under the enhanced runner"""
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
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',
1494
'bzrlib.tests.test_api',
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',
1502
'bzrlib.tests.test_commit',
1503
'bzrlib.tests.test_commit_merge',
1504
'bzrlib.tests.test_config',
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',
1515
'bzrlib.tests.test_hashcache',
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',
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',
1544
'bzrlib.tests.test_revisionnamespaces',
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',
1551
'bzrlib.tests.test_smart_add',
1552
'bzrlib.tests.test_smart_transport',
1553
'bzrlib.tests.test_source',
1554
'bzrlib.tests.test_status',
1555
'bzrlib.tests.test_store',
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',
1561
'bzrlib.tests.test_transactions',
1562
'bzrlib.tests.test_transform',
1563
'bzrlib.tests.test_transport',
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_version_info',
1574
'bzrlib.tests.test_weave',
1575
'bzrlib.tests.test_whitebox',
1576
'bzrlib.tests.test_workingtree',
1577
'bzrlib.tests.test_xml',
1579
test_transport_implementations = [
1580
'bzrlib.tests.test_transport_implementations',
1581
'bzrlib.tests.test_read_bundle',
1583
suite = TestUtil.TestSuite()
1584
loader = TestUtil.TestLoader()
1585
suite.addTest(loader.loadTestsFromModuleNames(testmod_names))
1586
from bzrlib.transport import TransportTestProviderAdapter
1587
adapter = TransportTestProviderAdapter()
1588
adapt_modules(test_transport_implementations, adapter, loader, suite)
1589
for package in packages_to_test():
1590
suite.addTest(package.test_suite())
1591
for m in MODULES_TO_TEST:
1592
suite.addTest(loader.loadTestsFromModule(m))
1593
for m in MODULES_TO_DOCTEST:
1594
suite.addTest(doctest.DocTestSuite(m))
1595
for name, plugin in bzrlib.plugin.all_plugins().items():
1596
if getattr(plugin, 'test_suite', None) is not None:
1597
suite.addTest(plugin.test_suite())
1601
def adapt_modules(mods_list, adapter, loader, suite):
1602
"""Adapt the modules in mods_list using adapter and add to suite."""
1603
for test in iter_suite_tests(loader.loadTestsFromModuleNames(mods_list)):
1604
suite.addTests(adapter.adapt(test))