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
44
import bzrlib.bzrdir as bzrdir
45
import bzrlib.commands
46
import bzrlib.errors as errors
47
import bzrlib.inventory
48
import bzrlib.iterablefile
50
from bzrlib.merge import merge_inner
53
import bzrlib.osutils as osutils
55
from bzrlib.revision import common_ancestor
58
from bzrlib.transport import urlescape, get_transport
59
import bzrlib.transport
60
from bzrlib.transport.local import LocalRelpathServer
61
from bzrlib.transport.readonly import ReadonlyServer
62
from bzrlib.trace import mutter
63
from bzrlib.tests.TestUtil import TestLoader, TestSuite
64
from bzrlib.tests.treeshape import build_tree_contents
65
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
67
default_transport = LocalRelpathServer
70
MODULES_TO_DOCTEST = [
82
def packages_to_test():
83
"""Return a list of packages to test.
85
The packages are not globally imported so that import failures are
86
triggered when running selftest, not when importing the command.
89
import bzrlib.tests.blackbox
90
import bzrlib.tests.branch_implementations
91
import bzrlib.tests.bzrdir_implementations
92
import bzrlib.tests.interrepository_implementations
93
import bzrlib.tests.interversionedfile_implementations
94
import bzrlib.tests.repository_implementations
95
import bzrlib.tests.revisionstore_implementations
96
import bzrlib.tests.workingtree_implementations
99
bzrlib.tests.blackbox,
100
bzrlib.tests.branch_implementations,
101
bzrlib.tests.bzrdir_implementations,
102
bzrlib.tests.interrepository_implementations,
103
bzrlib.tests.interversionedfile_implementations,
104
bzrlib.tests.repository_implementations,
105
bzrlib.tests.revisionstore_implementations,
106
bzrlib.tests.workingtree_implementations,
110
class _MyResult(unittest._TextTestResult):
111
"""Custom TestResult.
113
Shows output in a different format, including displaying runtime for tests.
117
def _elapsedTime(self):
118
return "%5dms" % (1000 * (time.time() - self._start_time))
120
def startTest(self, test):
121
unittest.TestResult.startTest(self, test)
122
# In a short description, the important words are in
123
# the beginning, but in an id, the important words are
125
SHOW_DESCRIPTIONS = False
127
width = osutils.terminal_width()
128
name_width = width - 15
130
if SHOW_DESCRIPTIONS:
131
what = test.shortDescription()
133
if len(what) > name_width:
134
what = what[:name_width-3] + '...'
137
if what.startswith('bzrlib.tests.'):
139
if len(what) > name_width:
140
what = '...' + what[3-name_width:]
141
what = what.ljust(name_width)
142
self.stream.write(what)
144
self._start_time = time.time()
146
def addError(self, test, err):
147
if isinstance(err[1], TestSkipped):
148
return self.addSkipped(test, err)
149
unittest.TestResult.addError(self, test, err)
151
self.stream.writeln("ERROR %s" % self._elapsedTime())
153
self.stream.write('E')
158
def addFailure(self, test, err):
159
unittest.TestResult.addFailure(self, test, err)
161
self.stream.writeln(" FAIL %s" % self._elapsedTime())
163
self.stream.write('F')
168
def addSuccess(self, test):
170
self.stream.writeln(' OK %s' % self._elapsedTime())
172
self.stream.write('~')
174
unittest.TestResult.addSuccess(self, test)
176
def addSkipped(self, test, skip_excinfo):
178
print >>self.stream, ' SKIP %s' % self._elapsedTime()
179
print >>self.stream, ' %s' % skip_excinfo[1]
181
self.stream.write('S')
183
# seems best to treat this as success from point-of-view of unittest
184
# -- it actually does nothing so it barely matters :)
185
unittest.TestResult.addSuccess(self, test)
187
def printErrorList(self, flavour, errors):
188
for test, err in errors:
189
self.stream.writeln(self.separator1)
190
self.stream.writeln("%s: %s" % (flavour, self.getDescription(test)))
191
if getattr(test, '_get_log', None) is not None:
193
print >>self.stream, \
194
('vvvv[log from %s]' % test.id()).ljust(78,'-')
195
print >>self.stream, test._get_log()
196
print >>self.stream, \
197
('^^^^[log from %s]' % test.id()).ljust(78,'-')
198
self.stream.writeln(self.separator2)
199
self.stream.writeln("%s" % err)
202
class TextTestRunner(unittest.TextTestRunner):
203
stop_on_failure = False
205
def _makeResult(self):
206
result = _MyResult(self.stream, self.descriptions, self.verbosity)
207
result.stop_early = self.stop_on_failure
211
def iter_suite_tests(suite):
212
"""Return all tests in a suite, recursing through nested suites"""
213
for item in suite._tests:
214
if isinstance(item, unittest.TestCase):
216
elif isinstance(item, unittest.TestSuite):
217
for r in iter_suite_tests(item):
220
raise Exception('unknown object %r inside test suite %r'
224
class TestSkipped(Exception):
225
"""Indicates that a test was intentionally skipped, rather than failing."""
229
class CommandFailed(Exception):
232
class TestCase(unittest.TestCase):
233
"""Base class for bzr unit tests.
235
Tests that need access to disk resources should subclass
236
TestCaseInTempDir not TestCase.
238
Error and debug log messages are redirected from their usual
239
location into a temporary file, the contents of which can be
240
retrieved by _get_log(). We use a real OS file, not an in-memory object,
241
so that it can also capture file IO. When the test completes this file
242
is read into memory and removed from disk.
244
There are also convenience functions to invoke bzr's command-line
245
routine, and to build and check bzr trees.
247
In addition to the usual method of overriding tearDown(), this class also
248
allows subclasses to register functions into the _cleanups list, which is
249
run in order as the object is torn down. It's less likely this will be
250
accidentally overlooked.
254
_log_file_name = None
257
def __init__(self, methodName='testMethod'):
258
super(TestCase, self).__init__(methodName)
262
unittest.TestCase.setUp(self)
263
self._cleanEnvironment()
264
bzrlib.trace.disable_default_logging()
267
def _ndiff_strings(self, a, b):
268
"""Return ndiff between two strings containing lines.
270
A trailing newline is added if missing to make the strings
272
if b and b[-1] != '\n':
274
if a and a[-1] != '\n':
276
difflines = difflib.ndiff(a.splitlines(True),
278
linejunk=lambda x: False,
279
charjunk=lambda x: False)
280
return ''.join(difflines)
282
def assertEqualDiff(self, a, b, message=None):
283
"""Assert two texts are equal, if not raise an exception.
285
This is intended for use with multi-line strings where it can
286
be hard to find the differences by eye.
288
# TODO: perhaps override assertEquals to call this for strings?
292
message = "texts not equal:\n"
293
raise AssertionError(message +
294
self._ndiff_strings(a, b))
296
def assertEqualMode(self, mode, mode_test):
297
self.assertEqual(mode, mode_test,
298
'mode mismatch %o != %o' % (mode, mode_test))
300
def assertStartsWith(self, s, prefix):
301
if not s.startswith(prefix):
302
raise AssertionError('string %r does not start with %r' % (s, prefix))
304
def assertEndsWith(self, s, suffix):
305
"""Asserts that s ends with suffix."""
306
if not s.endswith(suffix):
307
raise AssertionError('string %r does not end with %r' % (s, suffix))
309
def assertContainsRe(self, haystack, needle_re):
310
"""Assert that a contains something matching a regular expression."""
311
if not re.search(needle_re, haystack):
312
raise AssertionError('pattern "%s" not found in "%s"'
313
% (needle_re, haystack))
315
def assertSubset(self, sublist, superlist):
316
"""Assert that every entry in sublist is present in superlist."""
318
for entry in sublist:
319
if entry not in superlist:
320
missing.append(entry)
322
raise AssertionError("value(s) %r not present in container %r" %
323
(missing, superlist))
325
def assertIs(self, left, right):
326
if not (left is right):
327
raise AssertionError("%r is not %r." % (left, right))
329
def assertTransportMode(self, transport, path, mode):
330
"""Fail if a path does not have mode mode.
332
If modes are not supported on this transport, the assertion is ignored.
334
if not transport._can_roundtrip_unix_modebits():
336
path_stat = transport.stat(path)
337
actual_mode = stat.S_IMODE(path_stat.st_mode)
338
self.assertEqual(mode, actual_mode,
339
'mode of %r incorrect (%o != %o)' % (path, mode, actual_mode))
341
def assertIsInstance(self, obj, kls):
342
"""Fail if obj is not an instance of kls"""
343
if not isinstance(obj, kls):
344
self.fail("%r is an instance of %s rather than %s" % (
345
obj, obj.__class__, kls))
347
def _startLogFile(self):
348
"""Send bzr and test log messages to a temporary file.
350
The file is removed as the test is torn down.
352
fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
353
encoder, decoder, stream_reader, stream_writer = codecs.lookup('UTF-8')
354
self._log_file = stream_writer(os.fdopen(fileno, 'w+'))
355
self._log_nonce = bzrlib.trace.enable_test_log(self._log_file)
356
self._log_file_name = name
357
self.addCleanup(self._finishLogFile)
359
def _finishLogFile(self):
360
"""Finished with the log file.
362
Read contents into memory, close, and delete.
364
bzrlib.trace.disable_test_log(self._log_nonce)
365
self._log_file.seek(0)
366
self._log_contents = self._log_file.read()
367
self._log_file.close()
368
os.remove(self._log_file_name)
369
self._log_file = self._log_file_name = None
371
def addCleanup(self, callable):
372
"""Arrange to run a callable when this case is torn down.
374
Callables are run in the reverse of the order they are registered,
375
ie last-in first-out.
377
if callable in self._cleanups:
378
raise ValueError("cleanup function %r already registered on %s"
380
self._cleanups.append(callable)
382
def _cleanEnvironment(self):
385
'APPDATA': os.getcwd(),
390
self.addCleanup(self._restoreEnvironment)
391
for name, value in new_env.iteritems():
392
self._captureVar(name, value)
395
def _captureVar(self, name, newvalue):
396
"""Set an environment variable, preparing it to be reset when finished."""
397
self.__old_env[name] = os.environ.get(name, None)
399
if name in os.environ:
402
os.environ[name] = newvalue
405
def _restoreVar(name, value):
407
if name in os.environ:
410
os.environ[name] = value
412
def _restoreEnvironment(self):
413
for name, value in self.__old_env.iteritems():
414
self._restoreVar(name, value)
418
unittest.TestCase.tearDown(self)
420
def _runCleanups(self):
421
"""Run registered cleanup functions.
423
This should only be called from TestCase.tearDown.
425
# TODO: Perhaps this should keep running cleanups even if
427
for cleanup_fn in reversed(self._cleanups):
430
def log(self, *args):
434
"""Return as a string the log for this test"""
435
if self._log_file_name:
436
return open(self._log_file_name).read()
438
return self._log_contents
439
# TODO: Delete the log after it's been read in
441
def capture(self, cmd, retcode=0):
442
"""Shortcut that splits cmd into words, runs, and returns stdout"""
443
return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
445
def run_bzr_captured(self, argv, retcode=0, stdin=None):
446
"""Invoke bzr and return (stdout, stderr).
448
Useful for code that wants to check the contents of the
449
output, the way error messages are presented, etc.
451
This should be the main method for tests that want to exercise the
452
overall behavior of the bzr application (rather than a unit test
453
or a functional test of the library.)
455
Much of the old code runs bzr by forking a new copy of Python, but
456
that is slower, harder to debug, and generally not necessary.
458
This runs bzr through the interface that catches and reports
459
errors, and with logging set to something approximating the
460
default, so that error reporting can be checked.
462
argv -- arguments to invoke bzr
463
retcode -- expected return code, or None for don't-care.
464
:param stdin: A string to be used as stdin for the command.
466
if stdin is not None:
467
stdin = StringIO(stdin)
470
self.log('run bzr: %s', ' '.join(argv))
471
# FIXME: don't call into logging here
472
handler = logging.StreamHandler(stderr)
473
handler.setFormatter(bzrlib.trace.QuietFormatter())
474
handler.setLevel(logging.INFO)
475
logger = logging.getLogger('')
476
logger.addHandler(handler)
477
old_stdin = getattr(bzrlib.ui.ui_factory, "stdin", None)
478
bzrlib.ui.ui_factory.stdin = stdin
480
result = self.apply_redirected(stdin, stdout, stderr,
481
bzrlib.commands.run_bzr_catch_errors,
484
logger.removeHandler(handler)
485
bzrlib.ui.ui_factory.stdin = old_stdin
486
out = stdout.getvalue()
487
err = stderr.getvalue()
489
self.log('output:\n%s', out)
491
self.log('errors:\n%s', err)
492
if retcode is not None:
493
self.assertEquals(result, retcode)
496
def run_bzr(self, *args, **kwargs):
497
"""Invoke bzr, as if it were run from the command line.
499
This should be the main method for tests that want to exercise the
500
overall behavior of the bzr application (rather than a unit test
501
or a functional test of the library.)
503
This sends the stdout/stderr results into the test's log,
504
where it may be useful for debugging. See also run_captured.
506
:param stdin: A string to be used as stdin for the command.
508
retcode = kwargs.pop('retcode', 0)
509
stdin = kwargs.pop('stdin', None)
510
return self.run_bzr_captured(args, retcode, stdin)
512
def check_inventory_shape(self, inv, shape):
513
"""Compare an inventory to a list of expected names.
515
Fail if they are not precisely equal.
518
shape = list(shape) # copy
519
for path, ie in inv.entries():
520
name = path.replace('\\', '/')
528
self.fail("expected paths not found in inventory: %r" % shape)
530
self.fail("unexpected paths found in inventory: %r" % extras)
532
def apply_redirected(self, stdin=None, stdout=None, stderr=None,
533
a_callable=None, *args, **kwargs):
534
"""Call callable with redirected std io pipes.
536
Returns the return code."""
537
if not callable(a_callable):
538
raise ValueError("a_callable must be callable.")
542
if getattr(self, "_log_file", None) is not None:
543
stdout = self._log_file
547
if getattr(self, "_log_file", None is not None):
548
stderr = self._log_file
551
real_stdin = sys.stdin
552
real_stdout = sys.stdout
553
real_stderr = sys.stderr
558
return a_callable(*args, **kwargs)
560
sys.stdout = real_stdout
561
sys.stderr = real_stderr
562
sys.stdin = real_stdin
564
def merge(self, branch_from, wt_to):
565
"""A helper for tests to do a ui-less merge.
567
This should move to the main library when someone has time to integrate
570
# minimal ui-less merge.
571
wt_to.branch.fetch(branch_from)
572
base_rev = common_ancestor(branch_from.last_revision(),
573
wt_to.branch.last_revision(),
574
wt_to.branch.repository)
575
merge_inner(wt_to.branch, branch_from.basis_tree(),
576
wt_to.branch.repository.revision_tree(base_rev),
578
wt_to.add_pending_merge(branch_from.last_revision())
581
BzrTestBase = TestCase
584
class TestCaseInTempDir(TestCase):
585
"""Derived class that runs a test within a temporary directory.
587
This is useful for tests that need to create a branch, etc.
589
The directory is created in a slightly complex way: for each
590
Python invocation, a new temporary top-level directory is created.
591
All test cases create their own directory within that. If the
592
tests complete successfully, the directory is removed.
594
InTempDir is an old alias for FunctionalTestCase.
599
OVERRIDE_PYTHON = 'python'
601
def check_file_contents(self, filename, expect):
602
self.log("check contents of file %s" % filename)
603
contents = file(filename, 'r').read()
604
if contents != expect:
605
self.log("expected: %r" % expect)
606
self.log("actually: %r" % contents)
607
self.fail("contents of %s not as expected" % filename)
609
def _make_test_root(self):
610
if TestCaseInTempDir.TEST_ROOT is not None:
614
root = u'test%04d.tmp' % i
618
if e.errno == errno.EEXIST:
623
# successfully created
624
TestCaseInTempDir.TEST_ROOT = osutils.abspath(root)
626
# make a fake bzr directory there to prevent any tests propagating
627
# up onto the source directory's real branch
628
bzrdir.BzrDir.create_standalone_workingtree(TestCaseInTempDir.TEST_ROOT)
631
super(TestCaseInTempDir, self).setUp()
632
self._make_test_root()
633
_currentdir = os.getcwdu()
634
# shorten the name, to avoid test failures due to path length
635
short_id = self.id().replace('bzrlib.tests.', '') \
636
.replace('__main__.', '')[-100:]
637
# it's possible the same test class is run several times for
638
# parameterized tests, so make sure the names don't collide.
642
candidate_dir = '%s/%s.%d' % (self.TEST_ROOT, short_id, i)
644
candidate_dir = '%s/%s' % (self.TEST_ROOT, short_id)
645
if os.path.exists(candidate_dir):
649
self.test_dir = candidate_dir
650
os.mkdir(self.test_dir)
651
os.chdir(self.test_dir)
653
os.environ['HOME'] = self.test_dir
654
os.environ['APPDATA'] = self.test_dir
655
def _leaveDirectory():
656
os.chdir(_currentdir)
657
self.addCleanup(_leaveDirectory)
659
def build_tree(self, shape, line_endings='native', transport=None):
660
"""Build a test tree according to a pattern.
662
shape is a sequence of file specifications. If the final
663
character is '/', a directory is created.
665
This doesn't add anything to a branch.
666
:param line_endings: Either 'binary' or 'native'
667
in binary mode, exact contents are written
668
in native mode, the line endings match the
669
default platform endings.
671
:param transport: A transport to write to, for building trees on
672
VFS's. If the transport is readonly or None,
673
"." is opened automatically.
675
# XXX: It's OK to just create them using forward slashes on windows?
676
if transport is None or transport.is_readonly():
677
transport = get_transport(".")
679
self.assert_(isinstance(name, basestring))
681
transport.mkdir(urlescape(name[:-1]))
683
if line_endings == 'binary':
685
elif line_endings == 'native':
688
raise errors.BzrError('Invalid line ending request %r' % (line_endings,))
689
content = "contents of %s%s" % (name, end)
690
transport.put(urlescape(name), StringIO(content))
692
def build_tree_contents(self, shape):
693
build_tree_contents(shape)
695
def failUnlessExists(self, path):
696
"""Fail unless path, which may be abs or relative, exists."""
697
self.failUnless(osutils.lexists(path))
699
def failIfExists(self, path):
700
"""Fail if path, which may be abs or relative, exists."""
701
self.failIf(osutils.lexists(path))
703
def assertFileEqual(self, content, path):
704
"""Fail if path does not contain 'content'."""
705
self.failUnless(osutils.lexists(path))
706
self.assertEqualDiff(content, open(path, 'r').read())
709
class TestCaseWithTransport(TestCaseInTempDir):
710
"""A test case that provides get_url and get_readonly_url facilities.
712
These back onto two transport servers, one for readonly access and one for
715
If no explicit class is provided for readonly access, a
716
ReadonlyTransportDecorator is used instead which allows the use of non disk
717
based read write transports.
719
If an explicit class is provided for readonly access, that server and the
720
readwrite one must both define get_url() as resolving to os.getcwd().
723
def __init__(self, methodName='testMethod'):
724
super(TestCaseWithTransport, self).__init__(methodName)
725
self.__readonly_server = None
727
self.transport_server = default_transport
728
self.transport_readonly_server = None
730
def get_readonly_url(self, relpath=None):
731
"""Get a URL for the readonly transport.
733
This will either be backed by '.' or a decorator to the transport
734
used by self.get_url()
735
relpath provides for clients to get a path relative to the base url.
736
These should only be downwards relative, not upwards.
738
base = self.get_readonly_server().get_url()
739
if relpath is not None:
740
if not base.endswith('/'):
742
base = base + relpath
745
def get_readonly_server(self):
746
"""Get the server instance for the readonly transport
748
This is useful for some tests with specific servers to do diagnostics.
750
if self.__readonly_server is None:
751
if self.transport_readonly_server is None:
752
# readonly decorator requested
753
# bring up the server
755
self.__readonly_server = ReadonlyServer()
756
self.__readonly_server.setUp(self.__server)
758
self.__readonly_server = self.transport_readonly_server()
759
self.__readonly_server.setUp()
760
self.addCleanup(self.__readonly_server.tearDown)
761
return self.__readonly_server
763
def get_server(self):
764
"""Get the read/write server instance.
766
This is useful for some tests with specific servers that need
769
if self.__server is None:
770
self.__server = self.transport_server()
771
self.__server.setUp()
772
self.addCleanup(self.__server.tearDown)
775
def get_url(self, relpath=None):
776
"""Get a URL for the readwrite transport.
778
This will either be backed by '.' or to an equivalent non-file based
780
relpath provides for clients to get a path relative to the base url.
781
These should only be downwards relative, not upwards.
783
base = self.get_server().get_url()
784
if relpath is not None and relpath != '.':
785
if not base.endswith('/'):
787
base = base + relpath
790
def get_transport(self):
791
"""Return a writeable transport for the test scratch space"""
792
t = get_transport(self.get_url())
793
self.assertFalse(t.is_readonly())
796
def get_readonly_transport(self):
797
"""Return a readonly transport for the test scratch space
799
This can be used to test that operations which should only need
800
readonly access in fact do not try to write.
802
t = get_transport(self.get_readonly_url())
803
self.assertTrue(t.is_readonly())
806
def make_branch(self, relpath, format=None):
807
"""Create a branch on the transport at relpath."""
808
repo = self.make_repository(relpath, format=format)
809
return repo.bzrdir.create_branch()
811
def make_bzrdir(self, relpath, format=None):
813
url = self.get_url(relpath)
814
segments = relpath.split('/')
815
if segments and segments[-1] not in ('', '.'):
816
parent = self.get_url('/'.join(segments[:-1]))
817
t = get_transport(parent)
819
t.mkdir(segments[-1])
820
except errors.FileExists:
823
format=bzrlib.bzrdir.BzrDirFormat.get_default_format()
824
# FIXME: make this use a single transport someday. RBC 20060418
825
return format.initialize_on_transport(get_transport(relpath))
826
except errors.UninitializableFormat:
827
raise TestSkipped("Format %s is not initializable." % format)
829
def make_repository(self, relpath, shared=False, format=None):
830
"""Create a repository on our default transport at relpath."""
831
made_control = self.make_bzrdir(relpath, format=format)
832
return made_control.create_repository(shared=shared)
834
def make_branch_and_tree(self, relpath, format=None):
835
"""Create a branch on the transport and a tree locally.
839
# TODO: always use the local disk path for the working tree,
840
# this obviously requires a format that supports branch references
841
# so check for that by checking bzrdir.BzrDirFormat.get_default_format()
843
b = self.make_branch(relpath, format=format)
845
return b.bzrdir.create_workingtree()
846
except errors.NotLocalUrl:
847
# new formats - catch No tree error and create
848
# a branch reference and a checkout.
849
# old formats at that point - raise TestSkipped.
851
return WorkingTreeFormat2().initialize(bzrdir.BzrDir.open(relpath))
853
def assertIsDirectory(self, relpath, transport):
854
"""Assert that relpath within transport is a directory.
856
This may not be possible on all transports; in that case it propagates
857
a TransportNotPossible.
860
mode = transport.stat(relpath).st_mode
861
except errors.NoSuchFile:
862
self.fail("path %s is not a directory; no such file"
864
if not stat.S_ISDIR(mode):
865
self.fail("path %s is not a directory; has mode %#o"
869
class ChrootedTestCase(TestCaseWithTransport):
870
"""A support class that provides readonly urls outside the local namespace.
872
This is done by checking if self.transport_server is a MemoryServer. if it
873
is then we are chrooted already, if it is not then an HttpServer is used
876
TODO RBC 20060127: make this an option to TestCaseWithTransport so it can
877
be used without needed to redo it when a different
882
super(ChrootedTestCase, self).setUp()
883
if not self.transport_server == bzrlib.transport.memory.MemoryServer:
884
self.transport_readonly_server = bzrlib.transport.http.HttpServer
887
def filter_suite_by_re(suite, pattern):
889
filter_re = re.compile(pattern)
890
for test in iter_suite_tests(suite):
891
if filter_re.search(test.id()):
896
def run_suite(suite, name='test', verbose=False, pattern=".*",
897
stop_on_failure=False, keep_output=False,
899
TestCaseInTempDir._TEST_NAME = name
904
runner = TextTestRunner(stream=sys.stdout,
907
runner.stop_on_failure=stop_on_failure
909
suite = filter_suite_by_re(suite, pattern)
910
result = runner.run(suite)
911
# This is still a little bogus,
912
# but only a little. Folk not using our testrunner will
913
# have to delete their temp directories themselves.
914
test_root = TestCaseInTempDir.TEST_ROOT
915
if result.wasSuccessful() or not keep_output:
916
if test_root is not None:
917
print 'Deleting test root %s...' % test_root
919
osutils.rmtree(test_root)
923
print "Failed tests working directories are in '%s'\n" % TestCaseInTempDir.TEST_ROOT
924
return result.wasSuccessful()
927
def selftest(verbose=False, pattern=".*", stop_on_failure=True,
930
"""Run the whole test suite under the enhanced runner"""
931
global default_transport
932
if transport is None:
933
transport = default_transport
934
old_transport = default_transport
935
default_transport = transport
938
return run_suite(suite, 'testbzr', verbose=verbose, pattern=pattern,
939
stop_on_failure=stop_on_failure, keep_output=keep_output,
942
default_transport = old_transport
947
"""Build and return TestSuite for the whole program."""
948
from doctest import DocTestSuite
950
global MODULES_TO_DOCTEST
953
'bzrlib.tests.test_ancestry',
954
'bzrlib.tests.test_api',
955
'bzrlib.tests.test_bad_files',
956
'bzrlib.tests.test_branch',
957
'bzrlib.tests.test_bzrdir',
958
'bzrlib.tests.test_command',
959
'bzrlib.tests.test_commit',
960
'bzrlib.tests.test_commit_merge',
961
'bzrlib.tests.test_config',
962
'bzrlib.tests.test_conflicts',
963
'bzrlib.tests.test_decorators',
964
'bzrlib.tests.test_diff',
965
'bzrlib.tests.test_doc_generate',
966
'bzrlib.tests.test_errors',
967
'bzrlib.tests.test_escaped_store',
968
'bzrlib.tests.test_fetch',
969
'bzrlib.tests.test_gpg',
970
'bzrlib.tests.test_graph',
971
'bzrlib.tests.test_hashcache',
972
'bzrlib.tests.test_http',
973
'bzrlib.tests.test_identitymap',
974
'bzrlib.tests.test_inv',
975
'bzrlib.tests.test_knit',
976
'bzrlib.tests.test_lockdir',
977
'bzrlib.tests.test_lockable_files',
978
'bzrlib.tests.test_log',
979
'bzrlib.tests.test_merge',
980
'bzrlib.tests.test_merge3',
981
'bzrlib.tests.test_merge_core',
982
'bzrlib.tests.test_missing',
983
'bzrlib.tests.test_msgeditor',
984
'bzrlib.tests.test_nonascii',
985
'bzrlib.tests.test_options',
986
'bzrlib.tests.test_osutils',
987
'bzrlib.tests.test_patch',
988
'bzrlib.tests.test_permissions',
989
'bzrlib.tests.test_plugins',
990
'bzrlib.tests.test_progress',
991
'bzrlib.tests.test_reconcile',
992
'bzrlib.tests.test_repository',
993
'bzrlib.tests.test_revision',
994
'bzrlib.tests.test_revisionnamespaces',
995
'bzrlib.tests.test_revprops',
996
'bzrlib.tests.test_rio',
997
'bzrlib.tests.test_sampler',
998
'bzrlib.tests.test_selftest',
999
'bzrlib.tests.test_setup',
1000
'bzrlib.tests.test_sftp_transport',
1001
'bzrlib.tests.test_smart_add',
1002
'bzrlib.tests.test_source',
1003
'bzrlib.tests.test_store',
1004
'bzrlib.tests.test_symbol_versioning',
1005
'bzrlib.tests.test_testament',
1006
'bzrlib.tests.test_textfile',
1007
'bzrlib.tests.test_textmerge',
1008
'bzrlib.tests.test_trace',
1009
'bzrlib.tests.test_transactions',
1010
'bzrlib.tests.test_transform',
1011
'bzrlib.tests.test_transport',
1012
'bzrlib.tests.test_tsort',
1013
'bzrlib.tests.test_tuned_gzip',
1014
'bzrlib.tests.test_ui',
1015
'bzrlib.tests.test_upgrade',
1016
'bzrlib.tests.test_versionedfile',
1017
'bzrlib.tests.test_weave',
1018
'bzrlib.tests.test_whitebox',
1019
'bzrlib.tests.test_workingtree',
1020
'bzrlib.tests.test_xml',
1022
test_transport_implementations = [
1023
'bzrlib.tests.test_transport_implementations']
1025
TestCase.BZRPATH = osutils.pathjoin(
1026
osutils.realpath(osutils.dirname(bzrlib.__path__[0])), 'bzr')
1027
print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
1028
print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
1031
# python2.4's TestLoader.loadTestsFromNames gives very poor
1032
# errors if it fails to load a named module - no indication of what's
1033
# actually wrong, just "no such module". We should probably override that
1034
# class, but for the moment just load them ourselves. (mbp 20051202)
1035
loader = TestLoader()
1036
from bzrlib.transport import TransportTestProviderAdapter
1037
adapter = TransportTestProviderAdapter()
1038
adapt_modules(test_transport_implementations, adapter, loader, suite)
1039
for mod_name in testmod_names:
1040
mod = _load_module_by_name(mod_name)
1041
suite.addTest(loader.loadTestsFromModule(mod))
1042
for package in packages_to_test():
1043
suite.addTest(package.test_suite())
1044
for m in MODULES_TO_TEST:
1045
suite.addTest(loader.loadTestsFromModule(m))
1046
for m in (MODULES_TO_DOCTEST):
1047
suite.addTest(DocTestSuite(m))
1048
for name, plugin in bzrlib.plugin.all_plugins().items():
1049
if getattr(plugin, 'test_suite', None) is not None:
1050
suite.addTest(plugin.test_suite())
1054
def adapt_modules(mods_list, adapter, loader, suite):
1055
"""Adapt the modules in mods_list using adapter and add to suite."""
1056
for mod_name in mods_list:
1057
mod = _load_module_by_name(mod_name)
1058
for test in iter_suite_tests(loader.loadTestsFromModule(mod)):
1059
suite.addTests(adapter.adapt(test))
1062
def _load_module_by_name(mod_name):
1063
parts = mod_name.split('.')
1064
module = __import__(mod_name)
1066
# for historical reasons python returns the top-level module even though
1067
# it loads the submodule; we need to walk down to get the one we want.
1069
module = getattr(module, parts.pop(0))