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.
30
from cStringIO import StringIO
24
from testsweet import run_suite
45
import bzrlib.bzrdir as bzrdir
25
46
import bzrlib.commands
47
import bzrlib.errors as errors
48
import bzrlib.inventory
49
import bzrlib.iterablefile
51
from bzrlib.merge import merge_inner
54
import bzrlib.osutils as osutils
56
from bzrlib.revision import common_ancestor
27
58
import bzrlib.trace
59
from bzrlib.transport import urlescape, get_transport
60
import bzrlib.transport
61
from bzrlib.transport.local import LocalRelpathServer
62
from bzrlib.transport.readonly import ReadonlyServer
63
from bzrlib.trace import mutter
64
from bzrlib.tests.TestUtil import TestLoader, TestSuite
65
from bzrlib.tests.treeshape import build_tree_contents
66
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
68
default_transport = LocalRelpathServer
30
70
MODULES_TO_TEST = []
31
MODULES_TO_DOCTEST = []
33
from logging import debug, warning, error
71
MODULES_TO_DOCTEST = [
83
def packages_to_test():
84
"""Return a list of packages to test.
86
The packages are not globally imported so that import failures are
87
triggered when running selftest, not when importing the command.
90
import bzrlib.tests.blackbox
91
import bzrlib.tests.branch_implementations
92
import bzrlib.tests.bzrdir_implementations
93
import bzrlib.tests.interrepository_implementations
94
import bzrlib.tests.interversionedfile_implementations
95
import bzrlib.tests.repository_implementations
96
import bzrlib.tests.revisionstore_implementations
97
import bzrlib.tests.workingtree_implementations
100
bzrlib.tests.blackbox,
101
bzrlib.tests.branch_implementations,
102
bzrlib.tests.bzrdir_implementations,
103
bzrlib.tests.interrepository_implementations,
104
bzrlib.tests.interversionedfile_implementations,
105
bzrlib.tests.repository_implementations,
106
bzrlib.tests.revisionstore_implementations,
107
bzrlib.tests.workingtree_implementations,
111
class _MyResult(unittest._TextTestResult):
112
"""Custom TestResult.
114
Shows output in a different format, including displaying runtime for tests.
118
def _elapsedTime(self):
119
return "%5dms" % (1000 * (time.time() - self._start_time))
121
def startTest(self, test):
122
unittest.TestResult.startTest(self, test)
123
# In a short description, the important words are in
124
# the beginning, but in an id, the important words are
126
SHOW_DESCRIPTIONS = False
128
width = osutils.terminal_width()
129
name_width = width - 15
131
if SHOW_DESCRIPTIONS:
132
what = test.shortDescription()
134
if len(what) > name_width:
135
what = what[:name_width-3] + '...'
138
if what.startswith('bzrlib.tests.'):
140
if len(what) > name_width:
141
what = '...' + what[3-name_width:]
142
what = what.ljust(name_width)
143
self.stream.write(what)
145
self._start_time = time.time()
147
def addError(self, test, err):
148
if isinstance(err[1], TestSkipped):
149
return self.addSkipped(test, err)
150
unittest.TestResult.addError(self, test, err)
152
self.stream.writeln("ERROR %s" % self._elapsedTime())
154
self.stream.write('E')
159
def addFailure(self, test, err):
160
unittest.TestResult.addFailure(self, test, err)
162
self.stream.writeln(" FAIL %s" % self._elapsedTime())
164
self.stream.write('F')
169
def addSuccess(self, test):
171
self.stream.writeln(' OK %s' % self._elapsedTime())
173
self.stream.write('~')
175
unittest.TestResult.addSuccess(self, test)
177
def addSkipped(self, test, skip_excinfo):
179
print >>self.stream, ' SKIP %s' % self._elapsedTime()
180
print >>self.stream, ' %s' % skip_excinfo[1]
182
self.stream.write('S')
184
# seems best to treat this as success from point-of-view of unittest
185
# -- it actually does nothing so it barely matters :)
186
unittest.TestResult.addSuccess(self, test)
188
def printErrorList(self, flavour, errors):
189
for test, err in errors:
190
self.stream.writeln(self.separator1)
191
self.stream.writeln("%s: %s" % (flavour, self.getDescription(test)))
192
if getattr(test, '_get_log', None) is not None:
194
print >>self.stream, \
195
('vvvv[log from %s]' % test.id()).ljust(78,'-')
196
print >>self.stream, test._get_log()
197
print >>self.stream, \
198
('^^^^[log from %s]' % test.id()).ljust(78,'-')
199
self.stream.writeln(self.separator2)
200
self.stream.writeln("%s" % err)
203
class TextTestRunner(unittest.TextTestRunner):
204
stop_on_failure = False
206
def _makeResult(self):
207
result = _MyResult(self.stream, self.descriptions, self.verbosity)
208
result.stop_early = self.stop_on_failure
212
def iter_suite_tests(suite):
213
"""Return all tests in a suite, recursing through nested suites"""
214
for item in suite._tests:
215
if isinstance(item, unittest.TestCase):
217
elif isinstance(item, unittest.TestSuite):
218
for r in iter_suite_tests(item):
221
raise Exception('unknown object %r inside test suite %r'
225
class TestSkipped(Exception):
226
"""Indicates that a test was intentionally skipped, rather than failing."""
230
class CommandFailed(Exception):
234
class StringIOWrapper(object):
235
"""A wrapper around cStringIO which just adds an encoding attribute.
237
Internally we can check sys.stdout to see what the output encoding
238
should be. However, cStringIO has no encoding attribute that we can
239
set. So we wrap it instead.
244
def __init__(self, s=None):
246
self.__dict__['_cstring'] = StringIO(s)
248
self.__dict__['_cstring'] = StringIO()
250
def __getattr__(self, name, getattr=getattr):
251
return getattr(self.__dict__['_cstring'], name)
253
def __setattr__(self, name, val):
254
if name == 'encoding':
255
self.__dict__['encoding'] = val
257
return setattr(self._cstring, name, val)
36
260
class TestCase(unittest.TestCase):
42
266
Error and debug log messages are redirected from their usual
43
267
location into a temporary file, the contents of which can be
44
retrieved by _get_log().
268
retrieved by _get_log(). We use a real OS file, not an in-memory object,
269
so that it can also capture file IO. When the test completes this file
270
is read into memory and removed from disk.
46
272
There are also convenience functions to invoke bzr's command-line
47
routine, and to build and check bzr trees."""
273
routine, and to build and check bzr trees.
275
In addition to the usual method of overriding tearDown(), this class also
276
allows subclasses to register functions into the _cleanups list, which is
277
run in order as the object is torn down. It's less likely this will be
278
accidentally overlooked.
282
_log_file_name = None
285
def __init__(self, methodName='testMethod'):
286
super(TestCase, self).__init__(methodName)
52
# this replaces the default testsweet.TestCase; we don't want logging changed
53
290
unittest.TestCase.setUp(self)
291
self._cleanEnvironment()
54
292
bzrlib.trace.disable_default_logging()
55
self._enable_file_logging()
58
def _enable_file_logging(self):
295
def _ndiff_strings(self, a, b):
296
"""Return ndiff between two strings containing lines.
298
A trailing newline is added if missing to make the strings
300
if b and b[-1] != '\n':
302
if a and a[-1] != '\n':
304
difflines = difflib.ndiff(a.splitlines(True),
306
linejunk=lambda x: False,
307
charjunk=lambda x: False)
308
return ''.join(difflines)
310
def assertEqualDiff(self, a, b, message=None):
311
"""Assert two texts are equal, if not raise an exception.
313
This is intended for use with multi-line strings where it can
314
be hard to find the differences by eye.
316
# TODO: perhaps override assertEquals to call this for strings?
320
message = "texts not equal:\n"
321
raise AssertionError(message +
322
self._ndiff_strings(a, b))
324
def assertEqualMode(self, mode, mode_test):
325
self.assertEqual(mode, mode_test,
326
'mode mismatch %o != %o' % (mode, mode_test))
328
def assertStartsWith(self, s, prefix):
329
if not s.startswith(prefix):
330
raise AssertionError('string %r does not start with %r' % (s, prefix))
332
def assertEndsWith(self, s, suffix):
333
if not s.endswith(prefix):
334
raise AssertionError('string %r does not end with %r' % (s, suffix))
336
def assertContainsRe(self, haystack, needle_re):
337
"""Assert that a contains something matching a regular expression."""
338
if not re.search(needle_re, haystack):
339
raise AssertionError('pattern "%s" not found in "%s"'
340
% (needle_re, haystack))
342
def assertSubset(self, sublist, superlist):
343
"""Assert that every entry in sublist is present in superlist."""
345
for entry in sublist:
346
if entry not in superlist:
347
missing.append(entry)
349
raise AssertionError("value(s) %r not present in container %r" %
350
(missing, superlist))
352
def assertIs(self, left, right):
353
if not (left is right):
354
raise AssertionError("%r is not %r." % (left, right))
356
def assertTransportMode(self, transport, path, mode):
357
"""Fail if a path does not have mode mode.
359
If modes are not supported on this transport, the assertion is ignored.
361
if not transport._can_roundtrip_unix_modebits():
363
path_stat = transport.stat(path)
364
actual_mode = stat.S_IMODE(path_stat.st_mode)
365
self.assertEqual(mode, actual_mode,
366
'mode of %r incorrect (%o != %o)' % (path, mode, actual_mode))
368
def assertIsInstance(self, obj, kls):
369
"""Fail if obj is not an instance of kls"""
370
if not isinstance(obj, kls):
371
self.fail("%r is an instance of %s rather than %s" % (
372
obj, obj.__class__, kls))
374
def _startLogFile(self):
375
"""Send bzr and test log messages to a temporary file.
377
The file is removed as the test is torn down.
59
379
fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
61
self._log_file = os.fdopen(fileno, 'w+')
63
hdlr = logging.StreamHandler(self._log_file)
64
hdlr.setLevel(logging.DEBUG)
65
hdlr.setFormatter(logging.Formatter('%(levelname)4.4s %(message)s'))
66
logging.getLogger('').addHandler(hdlr)
67
logging.getLogger('').setLevel(logging.DEBUG)
69
debug('opened log file %s', name)
380
encoder, decoder, stream_reader, stream_writer = codecs.lookup('UTF-8')
381
self._log_file = stream_writer(os.fdopen(fileno, 'w+'))
382
self._log_nonce = bzrlib.trace.enable_test_log(self._log_file)
71
383
self._log_file_name = name
75
logging.getLogger('').removeHandler(self._log_hdlr)
76
bzrlib.trace.enable_default_logging()
77
logging.debug('%s teardown', self.id())
384
self.addCleanup(self._finishLogFile)
386
def _finishLogFile(self):
387
"""Finished with the log file.
389
Read contents into memory, close, and delete.
391
bzrlib.trace.disable_test_log(self._log_nonce)
392
self._log_file.seek(0)
393
self._log_contents = self._log_file.read()
78
394
self._log_file.close()
395
os.remove(self._log_file_name)
396
self._log_file = self._log_file_name = None
398
def addCleanup(self, callable):
399
"""Arrange to run a callable when this case is torn down.
401
Callables are run in the reverse of the order they are registered,
402
ie last-in first-out.
404
if callable in self._cleanups:
405
raise ValueError("cleanup function %r already registered on %s"
407
self._cleanups.append(callable)
409
def _cleanEnvironment(self):
412
'APPDATA': os.getcwd(),
417
self.addCleanup(self._restoreEnvironment)
418
for name, value in new_env.iteritems():
419
self._captureVar(name, value)
422
def _captureVar(self, name, newvalue):
423
"""Set an environment variable, preparing it to be reset when finished."""
424
self.__old_env[name] = os.environ.get(name, None)
426
if name in os.environ:
429
os.environ[name] = newvalue
432
def _restoreVar(name, value):
434
if name in os.environ:
437
os.environ[name] = value
439
def _restoreEnvironment(self):
440
for name, value in self.__old_env.iteritems():
441
self._restoreVar(name, value)
79
445
unittest.TestCase.tearDown(self)
447
def _runCleanups(self):
448
"""Run registered cleanup functions.
450
This should only be called from TestCase.tearDown.
452
# TODO: Perhaps this should keep running cleanups even if
454
for cleanup_fn in reversed(self._cleanups):
82
457
def log(self, *args):
85
460
def _get_log(self):
86
461
"""Return as a string the log for this test"""
87
return open(self._log_file_name).read()
462
if self._log_file_name:
463
return open(self._log_file_name).read()
465
return self._log_contents
466
# TODO: Delete the log after it's been read in
468
def capture(self, cmd, retcode=0):
469
"""Shortcut that splits cmd into words, runs, and returns stdout"""
470
return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
472
def run_bzr_captured(self, argv, retcode=0, encoding=None):
473
"""Invoke bzr and return (stdout, stderr).
475
Useful for code that wants to check the contents of the
476
output, the way error messages are presented, etc.
478
This should be the main method for tests that want to exercise the
479
overall behavior of the bzr application (rather than a unit test
480
or a functional test of the library.)
482
Much of the old code runs bzr by forking a new copy of Python, but
483
that is slower, harder to debug, and generally not necessary.
485
This runs bzr through the interface that catches and reports
486
errors, and with logging set to something approximating the
487
default, so that error reporting can be checked.
489
:param argv: arguments to invoke bzr
490
:param retcode: expected return code, or None for don't-care.
491
:param encoding: encoding for sys.stdout and sys.stderr
494
encoding = bzrlib.user_encoding
495
stdout = StringIOWrapper()
496
stderr = StringIOWrapper()
497
stdout.encoding = encoding
498
stderr.encoding = encoding
500
self.log('run bzr: %r', argv)
501
# FIXME: don't call into logging here
502
handler = logging.StreamHandler(stderr)
503
handler.setFormatter(bzrlib.trace.QuietFormatter())
504
handler.setLevel(logging.INFO)
505
logger = logging.getLogger('')
506
logger.addHandler(handler)
508
result = self.apply_redirected(None, stdout, stderr,
509
bzrlib.commands.run_bzr_catch_errors,
512
logger.removeHandler(handler)
513
# TODO: jam 20060105 Because we theoretically know the encoding
514
# of stdout and stderr, we could decode them at this time
515
# but for now, we will assume that the output of all
517
out = stdout.getvalue()
518
err = stderr.getvalue()
520
self.log('output:\n%r', out)
522
self.log('errors:\n%r', err)
523
if retcode is not None:
524
self.assertEquals(result, retcode)
89
527
def run_bzr(self, *args, **kwargs):
90
528
"""Invoke bzr, as if it were run from the command line.
178
640
if contents != expect:
179
641
self.log("expected: %r" % expect)
180
642
self.log("actually: %r" % contents)
181
self.fail("contents of %s not as expected")
643
self.fail("contents of %s not as expected" % filename)
183
645
def _make_test_root(self):
188
646
if TestCaseInTempDir.TEST_ROOT is not None:
190
TestCaseInTempDir.TEST_ROOT = os.path.abspath(
191
tempfile.mkdtemp(suffix='.tmp',
192
prefix=self._TEST_NAME + '-',
650
root = u'test%04d.tmp' % i
654
if e.errno == errno.EEXIST:
659
# successfully created
660
TestCaseInTempDir.TEST_ROOT = osutils.abspath(root)
195
662
# make a fake bzr directory there to prevent any tests propagating
196
663
# up onto the source directory's real branch
197
os.mkdir(os.path.join(TestCaseInTempDir.TEST_ROOT, '.bzr'))
664
bzrdir.BzrDir.create_standalone_workingtree(TestCaseInTempDir.TEST_ROOT)
200
667
super(TestCaseInTempDir, self).setUp()
202
668
self._make_test_root()
203
self._currentdir = os.getcwdu()
204
self.test_dir = os.path.join(self.TEST_ROOT, self.id())
205
os.mkdir(self.test_dir)
206
os.chdir(self.test_dir)
669
_currentdir = os.getcwdu()
670
# shorten the name, to avoid test failures due to path length
671
short_id = self.id().replace('bzrlib.tests.', '') \
672
.replace('__main__.', '')[-100:]
673
# it's possible the same test class is run several times for
674
# parameterized tests, so make sure the names don't collide.
678
candidate_dir = '%s/%s.%d' % (self.TEST_ROOT, short_id, i)
680
candidate_dir = '%s/%s' % (self.TEST_ROOT, short_id)
681
if os.path.exists(candidate_dir):
685
self.test_dir = candidate_dir
686
os.mkdir(self.test_dir)
687
os.chdir(self.test_dir)
689
os.environ['HOME'] = self.test_dir
690
os.environ['APPDATA'] = self.test_dir
691
def _leaveDirectory():
692
os.chdir(_currentdir)
693
self.addCleanup(_leaveDirectory)
210
os.chdir(self._currentdir)
211
super(TestCaseInTempDir, self).tearDown()
213
def _formcmd(self, cmd):
214
if isinstance(cmd, basestring):
217
cmd[0] = self.BZRPATH
218
if self.OVERRIDE_PYTHON:
219
cmd.insert(0, self.OVERRIDE_PYTHON)
220
self.log('$ %r' % cmd)
223
def runcmd(self, cmd, retcode=0):
224
"""Run one command and check the return code.
226
Returns a tuple of (stdout,stderr) strings.
228
If a single string is based, it is split into words.
229
For commands that are not simple space-separated words, please
230
pass a list instead."""
233
from subprocess import call
234
except ImportError, e:
237
cmd = self._formcmd(cmd)
238
self.log('$ ' + ' '.join(cmd))
239
actual_retcode = call(cmd, stdout=self._log_file, stderr=self._log_file)
240
if retcode != actual_retcode:
241
raise CommandFailed("test failed: %r returned %d, expected %d"
242
% (cmd, actual_retcode, retcode))
244
def backtick(self, cmd, retcode=0):
245
"""Run a command and return its output"""
248
from subprocess import Popen, PIPE
249
except ImportError, e:
253
cmd = self._formcmd(cmd)
254
child = Popen(cmd, stdout=PIPE, stderr=self._log_file)
255
outd, errd = child.communicate()
257
actual_retcode = child.wait()
259
outd = outd.replace('\r', '')
261
if retcode != actual_retcode:
262
raise CommandFailed("test failed: %r returned %d, expected %d"
263
% (cmd, actual_retcode, retcode))
269
def build_tree(self, shape):
695
def build_tree(self, shape, line_endings='native', transport=None):
270
696
"""Build a test tree according to a pattern.
272
698
shape is a sequence of file specifications. If the final
273
699
character is '/', a directory is created.
275
701
This doesn't add anything to a branch.
702
:param line_endings: Either 'binary' or 'native'
703
in binary mode, exact contents are written
704
in native mode, the line endings match the
705
default platform endings.
707
:param transport: A transport to write to, for building trees on
708
VFS's. If the transport is readonly or None,
709
"." is opened automatically.
277
711
# XXX: It's OK to just create them using forward slashes on windows?
712
if transport is None or transport.is_readonly():
713
transport = get_transport(".")
279
714
for name in shape:
280
assert isinstance(name, basestring)
715
self.assert_(isinstance(name, basestring))
281
716
if name[-1] == '/':
285
print >>f, "contents of", name
290
class MetaTestLog(TestCase):
291
def test_logging(self):
292
"""Test logs are captured when a test fails."""
293
logging.info('an info message')
294
warning('something looks dodgy...')
295
logging.debug('hello, test is running')
299
def selftest(verbose=False, pattern=".*"):
300
return run_suite(test_suite(), 'testbzr', verbose=verbose, pattern=pattern)
717
transport.mkdir(urlescape(name[:-1]))
719
if line_endings == 'binary':
721
elif line_endings == 'native':
724
raise errors.BzrError('Invalid line ending request %r' % (line_endings,))
725
content = "contents of %s%s" % (name.encode('utf-8'), end)
726
transport.put(urlescape(name), StringIO(content))
728
def build_tree_contents(self, shape):
729
build_tree_contents(shape)
731
def failUnlessExists(self, path):
732
"""Fail unless path, which may be abs or relative, exists."""
733
self.failUnless(osutils.lexists(path))
735
def failIfExists(self, path):
736
"""Fail if path, which may be abs or relative, exists."""
737
self.failIf(osutils.lexists(path))
739
def assertFileEqual(self, content, path):
740
"""Fail if path does not contain 'content'."""
741
self.failUnless(osutils.lexists(path))
742
self.assertEqualDiff(content, open(path, 'r').read())
745
class TestCaseWithTransport(TestCaseInTempDir):
746
"""A test case that provides get_url and get_readonly_url facilities.
748
These back onto two transport servers, one for readonly access and one for
751
If no explicit class is provided for readonly access, a
752
ReadonlyTransportDecorator is used instead which allows the use of non disk
753
based read write transports.
755
If an explicit class is provided for readonly access, that server and the
756
readwrite one must both define get_url() as resolving to os.getcwd().
759
def __init__(self, methodName='testMethod'):
760
super(TestCaseWithTransport, self).__init__(methodName)
761
self.__readonly_server = None
763
self.transport_server = default_transport
764
self.transport_readonly_server = None
766
def get_readonly_url(self, relpath=None):
767
"""Get a URL for the readonly transport.
769
This will either be backed by '.' or a decorator to the transport
770
used by self.get_url()
771
relpath provides for clients to get a path relative to the base url.
772
These should only be downwards relative, not upwards.
774
base = self.get_readonly_server().get_url()
775
if relpath is not None:
776
if not base.endswith('/'):
778
base = base + relpath
781
def get_readonly_server(self):
782
"""Get the server instance for the readonly transport
784
This is useful for some tests with specific servers to do diagnostics.
786
if self.__readonly_server is None:
787
if self.transport_readonly_server is None:
788
# readonly decorator requested
789
# bring up the server
791
self.__readonly_server = ReadonlyServer()
792
self.__readonly_server.setUp(self.__server)
794
self.__readonly_server = self.transport_readonly_server()
795
self.__readonly_server.setUp()
796
self.addCleanup(self.__readonly_server.tearDown)
797
return self.__readonly_server
799
def get_server(self):
800
"""Get the read/write server instance.
802
This is useful for some tests with specific servers that need
805
if self.__server is None:
806
self.__server = self.transport_server()
807
self.__server.setUp()
808
self.addCleanup(self.__server.tearDown)
811
def get_url(self, relpath=None):
812
"""Get a URL for the readwrite transport.
814
This will either be backed by '.' or to an equivalent non-file based
816
relpath provides for clients to get a path relative to the base url.
817
These should only be downwards relative, not upwards.
819
base = self.get_server().get_url()
820
if relpath is not None and relpath != '.':
821
if not base.endswith('/'):
823
base = base + relpath
826
def get_transport(self):
827
"""Return a writeable transport for the test scratch space"""
828
t = get_transport(self.get_url())
829
self.assertFalse(t.is_readonly())
832
def get_readonly_transport(self):
833
"""Return a readonly transport for the test scratch space
835
This can be used to test that operations which should only need
836
readonly access in fact do not try to write.
838
t = get_transport(self.get_readonly_url())
839
self.assertTrue(t.is_readonly())
842
def make_branch(self, relpath, format=None):
843
"""Create a branch on the transport at relpath."""
844
repo = self.make_repository(relpath, format=format)
845
return repo.bzrdir.create_branch()
847
def make_bzrdir(self, relpath, format=None):
849
url = self.get_url(relpath)
850
segments = relpath.split('/')
851
if segments and segments[-1] not in ('', '.'):
852
parent = self.get_url('/'.join(segments[:-1]))
853
t = get_transport(parent)
855
t.mkdir(segments[-1])
856
except errors.FileExists:
859
format=bzrlib.bzrdir.BzrDirFormat.get_default_format()
860
# FIXME: make this use a single transport someday. RBC 20060418
861
return format.initialize_on_transport(get_transport(relpath))
862
except errors.UninitializableFormat:
863
raise TestSkipped("Format %s is not initializable.")
865
def make_repository(self, relpath, shared=False, format=None):
866
"""Create a repository on our default transport at relpath."""
867
made_control = self.make_bzrdir(relpath, format=format)
868
return made_control.create_repository(shared=shared)
870
def make_branch_and_tree(self, relpath, format=None):
871
"""Create a branch on the transport and a tree locally.
875
# TODO: always use the local disk path for the working tree,
876
# this obviously requires a format that supports branch references
877
# so check for that by checking bzrdir.BzrDirFormat.get_default_format()
879
b = self.make_branch(relpath, format=format)
881
return b.bzrdir.create_workingtree()
882
except errors.NotLocalUrl:
883
# new formats - catch No tree error and create
884
# a branch reference and a checkout.
885
# old formats at that point - raise TestSkipped.
887
return WorkingTreeFormat2().initialize(bzrdir.BzrDir.open(relpath))
889
def assertIsDirectory(self, relpath, transport):
890
"""Assert that relpath within transport is a directory.
892
This may not be possible on all transports; in that case it propagates
893
a TransportNotPossible.
896
mode = transport.stat(relpath).st_mode
897
except errors.NoSuchFile:
898
self.fail("path %s is not a directory; no such file"
900
if not stat.S_ISDIR(mode):
901
self.fail("path %s is not a directory; has mode %#o"
905
class ChrootedTestCase(TestCaseWithTransport):
906
"""A support class that provides readonly urls outside the local namespace.
908
This is done by checking if self.transport_server is a MemoryServer. if it
909
is then we are chrooted already, if it is not then an HttpServer is used
912
TODO RBC 20060127: make this an option to TestCaseWithTransport so it can
913
be used without needed to redo it when a different
918
super(ChrootedTestCase, self).setUp()
919
if not self.transport_server == bzrlib.transport.memory.MemoryServer:
920
self.transport_readonly_server = bzrlib.transport.http.HttpServer
923
def filter_suite_by_re(suite, pattern):
925
filter_re = re.compile(pattern)
926
for test in iter_suite_tests(suite):
927
if filter_re.search(test.id()):
932
def run_suite(suite, name='test', verbose=False, pattern=".*",
933
stop_on_failure=False, keep_output=False,
935
TestCaseInTempDir._TEST_NAME = name
940
runner = TextTestRunner(stream=sys.stdout,
943
runner.stop_on_failure=stop_on_failure
945
suite = filter_suite_by_re(suite, pattern)
946
result = runner.run(suite)
947
# This is still a little bogus,
948
# but only a little. Folk not using our testrunner will
949
# have to delete their temp directories themselves.
950
test_root = TestCaseInTempDir.TEST_ROOT
951
if result.wasSuccessful() or not keep_output:
952
if test_root is not None:
953
print 'Deleting test root %s...' % test_root
955
shutil.rmtree(test_root)
959
print "Failed tests working directories are in '%s'\n" % TestCaseInTempDir.TEST_ROOT
960
return result.wasSuccessful()
963
def selftest(verbose=False, pattern=".*", stop_on_failure=True,
966
"""Run the whole test suite under the enhanced runner"""
967
global default_transport
968
if transport is None:
969
transport = default_transport
970
old_transport = default_transport
971
default_transport = transport
974
return run_suite(suite, 'testbzr', verbose=verbose, pattern=pattern,
975
stop_on_failure=stop_on_failure, keep_output=keep_output,
978
default_transport = old_transport
303
982
def test_suite():
304
from bzrlib.selftest.TestUtil import TestLoader, TestSuite
305
import bzrlib, bzrlib.store, bzrlib.inventory, bzrlib.branch
306
import bzrlib.osutils, bzrlib.commands, bzrlib.merge3, bzrlib.plugin
983
"""Build and return TestSuite for the whole program."""
307
984
from doctest import DocTestSuite
313
global MODULES_TO_TEST, MODULES_TO_DOCTEST
316
['bzrlib.selftest.MetaTestLog',
317
'bzrlib.selftest.testinv',
318
'bzrlib.selftest.testfetch',
319
'bzrlib.selftest.versioning',
320
'bzrlib.selftest.whitebox',
321
'bzrlib.selftest.testmerge3',
322
'bzrlib.selftest.testhashcache',
323
'bzrlib.selftest.teststatus',
324
'bzrlib.selftest.testlog',
325
'bzrlib.selftest.blackbox',
326
'bzrlib.selftest.testrevisionnamespaces',
327
'bzrlib.selftest.testbranch',
328
'bzrlib.selftest.testrevision',
329
'bzrlib.selftest.test_merge_core',
330
'bzrlib.selftest.test_smart_add',
331
'bzrlib.selftest.testdiff',
986
global MODULES_TO_DOCTEST
989
'bzrlib.tests.test_ancestry',
990
'bzrlib.tests.test_annotate',
991
'bzrlib.tests.test_api',
992
'bzrlib.tests.test_bad_files',
993
'bzrlib.tests.test_branch',
994
'bzrlib.tests.test_bzrdir',
995
'bzrlib.tests.test_command',
996
'bzrlib.tests.test_commit',
997
'bzrlib.tests.test_commit_merge',
998
'bzrlib.tests.test_config',
999
'bzrlib.tests.test_conflicts',
1000
'bzrlib.tests.test_decorators',
1001
'bzrlib.tests.test_diff',
1002
'bzrlib.tests.test_doc_generate',
1003
'bzrlib.tests.test_errors',
1004
'bzrlib.tests.test_escaped_store',
1005
'bzrlib.tests.test_fetch',
1006
'bzrlib.tests.test_gpg',
1007
'bzrlib.tests.test_graph',
1008
'bzrlib.tests.test_hashcache',
1009
'bzrlib.tests.test_http',
1010
'bzrlib.tests.test_identitymap',
1011
'bzrlib.tests.test_inv',
1012
'bzrlib.tests.test_knit',
1013
'bzrlib.tests.test_lockdir',
1014
'bzrlib.tests.test_lockable_files',
1015
'bzrlib.tests.test_log',
1016
'bzrlib.tests.test_merge',
1017
'bzrlib.tests.test_merge3',
1018
'bzrlib.tests.test_merge_core',
1019
'bzrlib.tests.test_missing',
1020
'bzrlib.tests.test_msgeditor',
1021
'bzrlib.tests.test_nonascii',
1022
'bzrlib.tests.test_options',
1023
'bzrlib.tests.test_osutils',
1024
'bzrlib.tests.test_patch',
1025
'bzrlib.tests.test_permissions',
1026
'bzrlib.tests.test_plugins',
1027
'bzrlib.tests.test_progress',
1028
'bzrlib.tests.test_reconcile',
1029
'bzrlib.tests.test_repository',
1030
'bzrlib.tests.test_revision',
1031
'bzrlib.tests.test_revisionnamespaces',
1032
'bzrlib.tests.test_revprops',
1033
'bzrlib.tests.test_rio',
1034
'bzrlib.tests.test_sampler',
1035
'bzrlib.tests.test_selftest',
1036
'bzrlib.tests.test_setup',
1037
'bzrlib.tests.test_sftp_transport',
1038
'bzrlib.tests.test_smart_add',
1039
'bzrlib.tests.test_source',
1040
'bzrlib.tests.test_store',
1041
'bzrlib.tests.test_symbol_versioning',
1042
'bzrlib.tests.test_testament',
1043
'bzrlib.tests.test_textfile',
1044
'bzrlib.tests.test_textmerge',
1045
'bzrlib.tests.test_trace',
1046
'bzrlib.tests.test_transactions',
1047
'bzrlib.tests.test_transform',
1048
'bzrlib.tests.test_transport',
1049
'bzrlib.tests.test_tsort',
1050
'bzrlib.tests.test_tuned_gzip',
1051
'bzrlib.tests.test_ui',
1052
'bzrlib.tests.test_upgrade',
1053
'bzrlib.tests.test_versionedfile',
1054
'bzrlib.tests.test_weave',
1055
'bzrlib.tests.test_whitebox',
1056
'bzrlib.tests.test_workingtree',
1057
'bzrlib.tests.test_xml',
335
for m in (bzrlib.store, bzrlib.inventory, bzrlib.branch,
336
bzrlib.osutils, bzrlib.commands, bzrlib.merge3):
337
if m not in MODULES_TO_DOCTEST:
338
MODULES_TO_DOCTEST.append(m)
340
TestCase.BZRPATH = os.path.join(os.path.realpath(os.path.dirname(bzrlib.__path__[0])), 'bzr')
341
print '%-30s %s' % ('bzr binary', TestCase.BZRPATH)
1059
test_transport_implementations = [
1060
'bzrlib.tests.test_transport_implementations']
1062
TestCase.BZRPATH = osutils.pathjoin(
1063
osutils.realpath(osutils.dirname(bzrlib.__path__[0])), 'bzr')
1064
print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
1065
print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
343
1067
suite = TestSuite()
344
suite.addTest(TestLoader().loadTestsFromNames(testmod_names))
1068
# python2.4's TestLoader.loadTestsFromNames gives very poor
1069
# errors if it fails to load a named module - no indication of what's
1070
# actually wrong, just "no such module". We should probably override that
1071
# class, but for the moment just load them ourselves. (mbp 20051202)
1072
loader = TestLoader()
1073
from bzrlib.transport import TransportTestProviderAdapter
1074
adapter = TransportTestProviderAdapter()
1075
adapt_modules(test_transport_implementations, adapter, loader, suite)
1076
for mod_name in testmod_names:
1077
mod = _load_module_by_name(mod_name)
1078
suite.addTest(loader.loadTestsFromModule(mod))
1079
for package in packages_to_test():
1080
suite.addTest(package.test_suite())
345
1081
for m in MODULES_TO_TEST:
346
suite.addTest(TestLoader().loadTestsFromModule(m))
1082
suite.addTest(loader.loadTestsFromModule(m))
347
1083
for m in (MODULES_TO_DOCTEST):
348
1084
suite.addTest(DocTestSuite(m))
349
for p in bzrlib.plugin.all_plugins:
350
if hasattr(p, 'test_suite'):
351
suite.addTest(p.test_suite())
1085
for name, plugin in bzrlib.plugin.all_plugins().items():
1086
if getattr(plugin, 'test_suite', None) is not None:
1087
suite.addTest(plugin.test_suite())
1091
def adapt_modules(mods_list, adapter, loader, suite):
1092
"""Adapt the modules in mods_list using adapter and add to suite."""
1093
for mod_name in mods_list:
1094
mod = _load_module_by_name(mod_name)
1095
for test in iter_suite_tests(loader.loadTestsFromModule(mod)):
1096
suite.addTests(adapter.adapt(test))
1099
def _load_module_by_name(mod_name):
1100
parts = mod_name.split('.')
1101
module = __import__(mod_name)
1103
# for historical reasons python returns the top-level module even though
1104
# it loads the submodule; we need to walk down to get the one we want.
1106
module = getattr(module, parts.pop(0))