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
25
from testsweet import run_suite
44
import bzrlib.bzrdir as bzrdir
26
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
import bzrlib.progress as progress
56
from bzrlib.revision import common_ancestor
28
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
32
70
MODULES_TO_TEST = []
33
MODULES_TO_DOCTEST = []
35
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 __init__(self, stream, descriptions, verbosity, pb=None):
119
unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
122
def _elapsedTime(self):
123
return "%5dms" % (1000 * (time.time() - self._start_time))
125
def _ellipsise_unimportant_words(self, a_string, final_width,
127
"""Add ellipsese (sp?) for overly long strings.
129
:param keep_start: If true preserve the start of a_string rather
133
if len(a_string) > final_width:
134
result = a_string[:final_width-3] + '...'
138
if len(a_string) > final_width:
139
result = '...' + a_string[3-final_width:]
142
return result.ljust(final_width)
144
def startTest(self, test):
145
unittest.TestResult.startTest(self, test)
146
# In a short description, the important words are in
147
# the beginning, but in an id, the important words are
149
SHOW_DESCRIPTIONS = False
151
if not self.showAll and self.dots and self.pb is not None:
154
final_width = osutils.terminal_width()
155
final_width = final_width - 15
157
if SHOW_DESCRIPTIONS:
158
what = test.shortDescription()
160
what = self._ellipsise_unimportant_words(what, final_width, keep_start=True)
163
if what.startswith('bzrlib.tests.'):
165
what = self._ellipsise_unimportant_words(what, final_width)
167
self.stream.write(what)
168
elif self.dots and self.pb is not None:
169
self.pb.update(what, self.testsRun - 1, None)
171
self._start_time = time.time()
173
def addError(self, test, err):
174
if isinstance(err[1], TestSkipped):
175
return self.addSkipped(test, err)
176
unittest.TestResult.addError(self, test, err)
178
self.stream.writeln("ERROR %s" % self._elapsedTime())
179
elif self.dots and self.pb is None:
180
self.stream.write('E')
182
self.pb.update(self._ellipsise_unimportant_words('ERROR', 13), self.testsRun, None)
187
def addFailure(self, test, err):
188
unittest.TestResult.addFailure(self, test, err)
190
self.stream.writeln(" FAIL %s" % self._elapsedTime())
191
elif self.dots and self.pb is None:
192
self.stream.write('F')
194
self.pb.update(self._ellipsise_unimportant_words('FAIL', 13), self.testsRun, None)
199
def addSuccess(self, test):
201
self.stream.writeln(' OK %s' % self._elapsedTime())
202
elif self.dots and self.pb is None:
203
self.stream.write('~')
205
self.pb.update(self._ellipsise_unimportant_words('OK', 13), self.testsRun, None)
207
unittest.TestResult.addSuccess(self, test)
209
def addSkipped(self, test, skip_excinfo):
211
print >>self.stream, ' SKIP %s' % self._elapsedTime()
212
print >>self.stream, ' %s' % skip_excinfo[1]
213
elif self.dots and self.pb is None:
214
self.stream.write('S')
216
self.pb.update(self._ellipsise_unimportant_words('SKIP', 13), self.testsRun, None)
218
# seems best to treat this as success from point-of-view of unittest
219
# -- it actually does nothing so it barely matters :)
220
unittest.TestResult.addSuccess(self, test)
222
def printErrorList(self, flavour, errors):
223
for test, err in errors:
224
self.stream.writeln(self.separator1)
225
self.stream.writeln("%s: %s" % (flavour, self.getDescription(test)))
226
if getattr(test, '_get_log', None) is not None:
228
print >>self.stream, \
229
('vvvv[log from %s]' % test.id()).ljust(78,'-')
230
print >>self.stream, test._get_log()
231
print >>self.stream, \
232
('^^^^[log from %s]' % test.id()).ljust(78,'-')
233
self.stream.writeln(self.separator2)
234
self.stream.writeln("%s" % err)
237
class TextTestRunner(object):
238
stop_on_failure = False
246
self.stream = unittest._WritelnDecorator(stream)
247
self.descriptions = descriptions
248
self.verbosity = verbosity
249
self.keep_output = keep_output
252
def _makeResult(self):
253
result = _MyResult(self.stream,
257
result.stop_early = self.stop_on_failure
261
"Run the given test case or test suite."
262
result = self._makeResult()
263
startTime = time.time()
264
if self.pb is not None:
265
self.pb.update('Running tests', 0, test.countTestCases())
267
stopTime = time.time()
268
timeTaken = stopTime - startTime
270
self.stream.writeln(result.separator2)
271
run = result.testsRun
272
self.stream.writeln("Ran %d test%s in %.3fs" %
273
(run, run != 1 and "s" or "", timeTaken))
274
self.stream.writeln()
275
if not result.wasSuccessful():
276
self.stream.write("FAILED (")
277
failed, errored = map(len, (result.failures, result.errors))
279
self.stream.write("failures=%d" % failed)
281
if failed: self.stream.write(", ")
282
self.stream.write("errors=%d" % errored)
283
self.stream.writeln(")")
285
self.stream.writeln("OK")
286
if self.pb is not None:
287
self.pb.update('Cleaning up', 0, 1)
288
# This is still a little bogus,
289
# but only a little. Folk not using our testrunner will
290
# have to delete their temp directories themselves.
291
test_root = TestCaseInTempDir.TEST_ROOT
292
if result.wasSuccessful() or not self.keep_output:
293
if test_root is not None:
294
osutils.rmtree(test_root)
296
if self.pb is not None:
297
self.pb.note("Failed tests working directories are in '%s'\n",
301
"Failed tests working directories are in '%s'\n" %
303
TestCaseInTempDir.TEST_ROOT = None
304
if self.pb is not None:
309
def iter_suite_tests(suite):
310
"""Return all tests in a suite, recursing through nested suites"""
311
for item in suite._tests:
312
if isinstance(item, unittest.TestCase):
314
elif isinstance(item, unittest.TestSuite):
315
for r in iter_suite_tests(item):
318
raise Exception('unknown object %r inside test suite %r'
322
class TestSkipped(Exception):
323
"""Indicates that a test was intentionally skipped, rather than failing."""
37
327
class CommandFailed(Exception):
46
336
Error and debug log messages are redirected from their usual
47
337
location into a temporary file, the contents of which can be
48
retrieved by _get_log().
338
retrieved by _get_log(). We use a real OS file, not an in-memory object,
339
so that it can also capture file IO. When the test completes this file
340
is read into memory and removed from disk.
50
342
There are also convenience functions to invoke bzr's command-line
51
routine, and to build and check bzr trees."""
343
routine, and to build and check bzr trees.
345
In addition to the usual method of overriding tearDown(), this class also
346
allows subclasses to register functions into the _cleanups list, which is
347
run in order as the object is torn down. It's less likely this will be
348
accidentally overlooked.
352
_log_file_name = None
355
def __init__(self, methodName='testMethod'):
356
super(TestCase, self).__init__(methodName)
56
# this replaces the default testsweet.TestCase; we don't want logging changed
57
360
unittest.TestCase.setUp(self)
361
self._cleanEnvironment()
58
362
bzrlib.trace.disable_default_logging()
59
self._enable_file_logging()
62
def _enable_file_logging(self):
365
def _ndiff_strings(self, a, b):
366
"""Return ndiff between two strings containing lines.
368
A trailing newline is added if missing to make the strings
370
if b and b[-1] != '\n':
372
if a and a[-1] != '\n':
374
difflines = difflib.ndiff(a.splitlines(True),
376
linejunk=lambda x: False,
377
charjunk=lambda x: False)
378
return ''.join(difflines)
380
def assertEqualDiff(self, a, b, message=None):
381
"""Assert two texts are equal, if not raise an exception.
383
This is intended for use with multi-line strings where it can
384
be hard to find the differences by eye.
386
# TODO: perhaps override assertEquals to call this for strings?
390
message = "texts not equal:\n"
391
raise AssertionError(message +
392
self._ndiff_strings(a, b))
394
def assertEqualMode(self, mode, mode_test):
395
self.assertEqual(mode, mode_test,
396
'mode mismatch %o != %o' % (mode, mode_test))
398
def assertStartsWith(self, s, prefix):
399
if not s.startswith(prefix):
400
raise AssertionError('string %r does not start with %r' % (s, prefix))
402
def assertEndsWith(self, s, suffix):
403
"""Asserts that s ends with suffix."""
404
if not s.endswith(suffix):
405
raise AssertionError('string %r does not end with %r' % (s, suffix))
407
def assertContainsRe(self, haystack, needle_re):
408
"""Assert that a contains something matching a regular expression."""
409
if not re.search(needle_re, haystack):
410
raise AssertionError('pattern "%s" not found in "%s"'
411
% (needle_re, haystack))
413
def assertSubset(self, sublist, superlist):
414
"""Assert that every entry in sublist is present in superlist."""
416
for entry in sublist:
417
if entry not in superlist:
418
missing.append(entry)
420
raise AssertionError("value(s) %r not present in container %r" %
421
(missing, superlist))
423
def assertIs(self, left, right):
424
if not (left is right):
425
raise AssertionError("%r is not %r." % (left, right))
427
def assertTransportMode(self, transport, path, mode):
428
"""Fail if a path does not have mode mode.
430
If modes are not supported on this transport, the assertion is ignored.
432
if not transport._can_roundtrip_unix_modebits():
434
path_stat = transport.stat(path)
435
actual_mode = stat.S_IMODE(path_stat.st_mode)
436
self.assertEqual(mode, actual_mode,
437
'mode of %r incorrect (%o != %o)' % (path, mode, actual_mode))
439
def assertIsInstance(self, obj, kls):
440
"""Fail if obj is not an instance of kls"""
441
if not isinstance(obj, kls):
442
self.fail("%r is an instance of %s rather than %s" % (
443
obj, obj.__class__, kls))
445
def _startLogFile(self):
446
"""Send bzr and test log messages to a temporary file.
448
The file is removed as the test is torn down.
63
450
fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
65
self._log_file = os.fdopen(fileno, 'w+')
67
hdlr = logging.StreamHandler(self._log_file)
68
hdlr.setLevel(logging.DEBUG)
69
hdlr.setFormatter(logging.Formatter('%(levelname)8s %(message)s'))
70
logging.getLogger('').addHandler(hdlr)
71
logging.getLogger('').setLevel(logging.DEBUG)
73
debug('opened log file %s', name)
451
encoder, decoder, stream_reader, stream_writer = codecs.lookup('UTF-8')
452
self._log_file = stream_writer(os.fdopen(fileno, 'w+'))
453
self._log_nonce = bzrlib.trace.enable_test_log(self._log_file)
75
454
self._log_file_name = name
79
logging.getLogger('').removeHandler(self._log_hdlr)
80
bzrlib.trace.enable_default_logging()
81
logging.debug('%s teardown', self.id())
455
self.addCleanup(self._finishLogFile)
457
def _finishLogFile(self):
458
"""Finished with the log file.
460
Read contents into memory, close, and delete.
462
bzrlib.trace.disable_test_log(self._log_nonce)
463
self._log_file.seek(0)
464
self._log_contents = self._log_file.read()
82
465
self._log_file.close()
466
os.remove(self._log_file_name)
467
self._log_file = self._log_file_name = None
469
def addCleanup(self, callable):
470
"""Arrange to run a callable when this case is torn down.
472
Callables are run in the reverse of the order they are registered,
473
ie last-in first-out.
475
if callable in self._cleanups:
476
raise ValueError("cleanup function %r already registered on %s"
478
self._cleanups.append(callable)
480
def _cleanEnvironment(self):
483
'APPDATA': os.getcwd(),
488
self.addCleanup(self._restoreEnvironment)
489
for name, value in new_env.iteritems():
490
self._captureVar(name, value)
493
def _captureVar(self, name, newvalue):
494
"""Set an environment variable, preparing it to be reset when finished."""
495
self.__old_env[name] = os.environ.get(name, None)
497
if name in os.environ:
500
os.environ[name] = newvalue
503
def _restoreVar(name, value):
505
if name in os.environ:
508
os.environ[name] = value
510
def _restoreEnvironment(self):
511
for name, value in self.__old_env.iteritems():
512
self._restoreVar(name, value)
83
516
unittest.TestCase.tearDown(self)
518
def _runCleanups(self):
519
"""Run registered cleanup functions.
521
This should only be called from TestCase.tearDown.
523
# TODO: Perhaps this should keep running cleanups even if
525
for cleanup_fn in reversed(self._cleanups):
86
528
def log(self, *args):
89
531
def _get_log(self):
90
532
"""Return as a string the log for this test"""
91
return open(self._log_file_name).read()
533
if self._log_file_name:
534
return open(self._log_file_name).read()
536
return self._log_contents
537
# TODO: Delete the log after it's been read in
539
def capture(self, cmd, retcode=0):
540
"""Shortcut that splits cmd into words, runs, and returns stdout"""
541
return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
543
def run_bzr_captured(self, argv, retcode=0, stdin=None):
544
"""Invoke bzr and return (stdout, stderr).
546
Useful for code that wants to check the contents of the
547
output, the way error messages are presented, etc.
549
This should be the main method for tests that want to exercise the
550
overall behavior of the bzr application (rather than a unit test
551
or a functional test of the library.)
553
Much of the old code runs bzr by forking a new copy of Python, but
554
that is slower, harder to debug, and generally not necessary.
556
This runs bzr through the interface that catches and reports
557
errors, and with logging set to something approximating the
558
default, so that error reporting can be checked.
560
argv -- arguments to invoke bzr
561
retcode -- expected return code, or None for don't-care.
562
:param stdin: A string to be used as stdin for the command.
564
if stdin is not None:
565
stdin = StringIO(stdin)
568
self.log('run bzr: %s', ' '.join(argv))
569
# FIXME: don't call into logging here
570
handler = logging.StreamHandler(stderr)
571
handler.setFormatter(bzrlib.trace.QuietFormatter())
572
handler.setLevel(logging.INFO)
573
logger = logging.getLogger('')
574
logger.addHandler(handler)
575
old_ui_factory = bzrlib.ui.ui_factory
576
bzrlib.ui.ui_factory = bzrlib.tests.blackbox.TestUIFactory(
579
bzrlib.ui.ui_factory.stdin = stdin
581
result = self.apply_redirected(stdin, stdout, stderr,
582
bzrlib.commands.run_bzr_catch_errors,
585
logger.removeHandler(handler)
586
bzrlib.ui.ui_factory = old_ui_factory
587
out = stdout.getvalue()
588
err = stderr.getvalue()
590
self.log('output:\n%s', out)
592
self.log('errors:\n%s', err)
593
if retcode is not None:
594
self.assertEquals(result, retcode)
93
597
def run_bzr(self, *args, **kwargs):
94
598
"""Invoke bzr, as if it were run from the command line.
181
705
if contents != expect:
182
706
self.log("expected: %r" % expect)
183
707
self.log("actually: %r" % contents)
184
self.fail("contents of %s not as expected")
708
self.fail("contents of %s not as expected" % filename)
186
710
def _make_test_root(self):
191
711
if TestCaseInTempDir.TEST_ROOT is not None:
193
TestCaseInTempDir.TEST_ROOT = os.path.abspath(
194
tempfile.mkdtemp(suffix='.tmp',
195
prefix=self._TEST_NAME + '-',
715
root = u'test%04d.tmp' % i
719
if e.errno == errno.EEXIST:
724
# successfully created
725
TestCaseInTempDir.TEST_ROOT = osutils.abspath(root)
198
727
# make a fake bzr directory there to prevent any tests propagating
199
728
# up onto the source directory's real branch
200
os.mkdir(os.path.join(TestCaseInTempDir.TEST_ROOT, '.bzr'))
729
bzrdir.BzrDir.create_standalone_workingtree(TestCaseInTempDir.TEST_ROOT)
203
732
super(TestCaseInTempDir, self).setUp()
205
733
self._make_test_root()
206
self._currentdir = os.getcwdu()
207
short_id = self.id().replace('bzrlib.selftest.', '')
208
self.test_dir = os.path.join(self.TEST_ROOT, short_id)
209
os.mkdir(self.test_dir)
210
os.chdir(self.test_dir)
734
_currentdir = os.getcwdu()
735
# shorten the name, to avoid test failures due to path length
736
short_id = self.id().replace('bzrlib.tests.', '') \
737
.replace('__main__.', '')[-100:]
738
# it's possible the same test class is run several times for
739
# parameterized tests, so make sure the names don't collide.
743
candidate_dir = '%s/%s.%d' % (self.TEST_ROOT, short_id, i)
745
candidate_dir = '%s/%s' % (self.TEST_ROOT, short_id)
746
if os.path.exists(candidate_dir):
750
self.test_dir = candidate_dir
751
os.mkdir(self.test_dir)
752
os.chdir(self.test_dir)
754
os.environ['HOME'] = self.test_dir
755
os.environ['APPDATA'] = self.test_dir
756
def _leaveDirectory():
757
os.chdir(_currentdir)
758
self.addCleanup(_leaveDirectory)
214
os.chdir(self._currentdir)
215
super(TestCaseInTempDir, self).tearDown()
217
def _formcmd(self, cmd):
218
if isinstance(cmd, basestring):
221
cmd[0] = self.BZRPATH
222
if self.OVERRIDE_PYTHON:
223
cmd.insert(0, self.OVERRIDE_PYTHON)
224
self.log('$ %r' % cmd)
227
def runcmd(self, cmd, retcode=0):
228
"""Run one command and check the return code.
230
Returns a tuple of (stdout,stderr) strings.
232
If a single string is based, it is split into words.
233
For commands that are not simple space-separated words, please
234
pass a list instead."""
235
cmd = self._formcmd(cmd)
236
self.log('$ ' + ' '.join(cmd))
237
actual_retcode = subprocess.call(cmd, stdout=self._log_file,
238
stderr=self._log_file)
239
if retcode != actual_retcode:
240
raise CommandFailed("test failed: %r returned %d, expected %d"
241
% (cmd, actual_retcode, retcode))
243
def backtick(self, cmd, retcode=0):
244
"""Run a command and return its output"""
245
cmd = self._formcmd(cmd)
246
child = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=self._log_file)
247
outd, errd = child.communicate()
249
actual_retcode = child.wait()
251
outd = outd.replace('\r', '')
253
if retcode != actual_retcode:
254
raise CommandFailed("test failed: %r returned %d, expected %d"
255
% (cmd, actual_retcode, retcode))
261
def build_tree(self, shape):
760
def build_tree(self, shape, line_endings='native', transport=None):
262
761
"""Build a test tree according to a pattern.
264
763
shape is a sequence of file specifications. If the final
265
764
character is '/', a directory is created.
267
766
This doesn't add anything to a branch.
767
:param line_endings: Either 'binary' or 'native'
768
in binary mode, exact contents are written
769
in native mode, the line endings match the
770
default platform endings.
772
:param transport: A transport to write to, for building trees on
773
VFS's. If the transport is readonly or None,
774
"." is opened automatically.
269
776
# XXX: It's OK to just create them using forward slashes on windows?
777
if transport is None or transport.is_readonly():
778
transport = get_transport(".")
271
779
for name in shape:
272
assert isinstance(name, basestring)
780
self.assert_(isinstance(name, basestring))
273
781
if name[-1] == '/':
277
print >>f, "contents of", name
282
class MetaTestLog(TestCase):
283
def test_logging(self):
284
"""Test logs are captured when a test fails."""
285
logging.info('an info message')
286
warning('something looks dodgy...')
287
logging.debug('hello, test is running')
291
def selftest(verbose=False, pattern=".*"):
782
transport.mkdir(urlescape(name[:-1]))
784
if line_endings == 'binary':
786
elif line_endings == 'native':
789
raise errors.BzrError('Invalid line ending request %r' % (line_endings,))
790
content = "contents of %s%s" % (name, end)
791
transport.put(urlescape(name), StringIO(content))
793
def build_tree_contents(self, shape):
794
build_tree_contents(shape)
796
def failUnlessExists(self, path):
797
"""Fail unless path, which may be abs or relative, exists."""
798
self.failUnless(osutils.lexists(path))
800
def failIfExists(self, path):
801
"""Fail if path, which may be abs or relative, exists."""
802
self.failIf(osutils.lexists(path))
804
def assertFileEqual(self, content, path):
805
"""Fail if path does not contain 'content'."""
806
self.failUnless(osutils.lexists(path))
807
self.assertEqualDiff(content, open(path, 'r').read())
810
class TestCaseWithTransport(TestCaseInTempDir):
811
"""A test case that provides get_url and get_readonly_url facilities.
813
These back onto two transport servers, one for readonly access and one for
816
If no explicit class is provided for readonly access, a
817
ReadonlyTransportDecorator is used instead which allows the use of non disk
818
based read write transports.
820
If an explicit class is provided for readonly access, that server and the
821
readwrite one must both define get_url() as resolving to os.getcwd().
824
def __init__(self, methodName='testMethod'):
825
super(TestCaseWithTransport, self).__init__(methodName)
826
self.__readonly_server = None
828
self.transport_server = default_transport
829
self.transport_readonly_server = None
831
def get_readonly_url(self, relpath=None):
832
"""Get a URL for the readonly transport.
834
This will either be backed by '.' or a decorator to the transport
835
used by self.get_url()
836
relpath provides for clients to get a path relative to the base url.
837
These should only be downwards relative, not upwards.
839
base = self.get_readonly_server().get_url()
840
if relpath is not None:
841
if not base.endswith('/'):
843
base = base + relpath
846
def get_readonly_server(self):
847
"""Get the server instance for the readonly transport
849
This is useful for some tests with specific servers to do diagnostics.
851
if self.__readonly_server is None:
852
if self.transport_readonly_server is None:
853
# readonly decorator requested
854
# bring up the server
856
self.__readonly_server = ReadonlyServer()
857
self.__readonly_server.setUp(self.__server)
859
self.__readonly_server = self.transport_readonly_server()
860
self.__readonly_server.setUp()
861
self.addCleanup(self.__readonly_server.tearDown)
862
return self.__readonly_server
864
def get_server(self):
865
"""Get the read/write server instance.
867
This is useful for some tests with specific servers that need
870
if self.__server is None:
871
self.__server = self.transport_server()
872
self.__server.setUp()
873
self.addCleanup(self.__server.tearDown)
876
def get_url(self, relpath=None):
877
"""Get a URL for the readwrite transport.
879
This will either be backed by '.' or to an equivalent non-file based
881
relpath provides for clients to get a path relative to the base url.
882
These should only be downwards relative, not upwards.
884
base = self.get_server().get_url()
885
if relpath is not None and relpath != '.':
886
if not base.endswith('/'):
888
base = base + relpath
891
def get_transport(self):
892
"""Return a writeable transport for the test scratch space"""
893
t = get_transport(self.get_url())
894
self.assertFalse(t.is_readonly())
897
def get_readonly_transport(self):
898
"""Return a readonly transport for the test scratch space
900
This can be used to test that operations which should only need
901
readonly access in fact do not try to write.
903
t = get_transport(self.get_readonly_url())
904
self.assertTrue(t.is_readonly())
907
def make_branch(self, relpath, format=None):
908
"""Create a branch on the transport at relpath."""
909
repo = self.make_repository(relpath, format=format)
910
return repo.bzrdir.create_branch()
912
def make_bzrdir(self, relpath, format=None):
914
url = self.get_url(relpath)
915
segments = relpath.split('/')
916
if segments and segments[-1] not in ('', '.'):
917
parent = self.get_url('/'.join(segments[:-1]))
918
t = get_transport(parent)
920
t.mkdir(segments[-1])
921
except errors.FileExists:
924
format=bzrlib.bzrdir.BzrDirFormat.get_default_format()
925
# FIXME: make this use a single transport someday. RBC 20060418
926
return format.initialize_on_transport(get_transport(relpath))
927
except errors.UninitializableFormat:
928
raise TestSkipped("Format %s is not initializable." % format)
930
def make_repository(self, relpath, shared=False, format=None):
931
"""Create a repository on our default transport at relpath."""
932
made_control = self.make_bzrdir(relpath, format=format)
933
return made_control.create_repository(shared=shared)
935
def make_branch_and_tree(self, relpath, format=None):
936
"""Create a branch on the transport and a tree locally.
940
# TODO: always use the local disk path for the working tree,
941
# this obviously requires a format that supports branch references
942
# so check for that by checking bzrdir.BzrDirFormat.get_default_format()
944
b = self.make_branch(relpath, format=format)
946
return b.bzrdir.create_workingtree()
947
except errors.NotLocalUrl:
948
# new formats - catch No tree error and create
949
# a branch reference and a checkout.
950
# old formats at that point - raise TestSkipped.
952
return WorkingTreeFormat2().initialize(bzrdir.BzrDir.open(relpath))
954
def assertIsDirectory(self, relpath, transport):
955
"""Assert that relpath within transport is a directory.
957
This may not be possible on all transports; in that case it propagates
958
a TransportNotPossible.
961
mode = transport.stat(relpath).st_mode
962
except errors.NoSuchFile:
963
self.fail("path %s is not a directory; no such file"
965
if not stat.S_ISDIR(mode):
966
self.fail("path %s is not a directory; has mode %#o"
970
class ChrootedTestCase(TestCaseWithTransport):
971
"""A support class that provides readonly urls outside the local namespace.
973
This is done by checking if self.transport_server is a MemoryServer. if it
974
is then we are chrooted already, if it is not then an HttpServer is used
977
TODO RBC 20060127: make this an option to TestCaseWithTransport so it can
978
be used without needed to redo it when a different
983
super(ChrootedTestCase, self).setUp()
984
if not self.transport_server == bzrlib.transport.memory.MemoryServer:
985
self.transport_readonly_server = bzrlib.transport.http.HttpServer
988
def filter_suite_by_re(suite, pattern):
990
filter_re = re.compile(pattern)
991
for test in iter_suite_tests(suite):
992
if filter_re.search(test.id()):
997
def run_suite(suite, name='test', verbose=False, pattern=".*",
998
stop_on_failure=False, keep_output=False,
1000
TestCaseInTempDir._TEST_NAME = name
1006
pb = progress.ProgressBar()
1007
runner = TextTestRunner(stream=sys.stdout,
1009
verbosity=verbosity,
1010
keep_output=keep_output,
1012
runner.stop_on_failure=stop_on_failure
1014
suite = filter_suite_by_re(suite, pattern)
1015
result = runner.run(suite)
1016
return result.wasSuccessful()
1019
def selftest(verbose=False, pattern=".*", stop_on_failure=True,
292
1022
"""Run the whole test suite under the enhanced runner"""
293
return run_suite(test_suite(), 'testbzr', verbose=verbose, pattern=pattern)
1023
global default_transport
1024
if transport is None:
1025
transport = default_transport
1026
old_transport = default_transport
1027
default_transport = transport
1028
suite = test_suite()
1030
return run_suite(suite, 'testbzr', verbose=verbose, pattern=pattern,
1031
stop_on_failure=stop_on_failure, keep_output=keep_output,
1032
transport=transport)
1034
default_transport = old_transport
296
1038
def test_suite():
297
1039
"""Build and return TestSuite for the whole program."""
298
from bzrlib.selftest.TestUtil import TestLoader, TestSuite
299
import bzrlib, bzrlib.store, bzrlib.inventory, bzrlib.branch
300
import bzrlib.osutils, bzrlib.commands, bzrlib.merge3, bzrlib.plugin
301
1040
from doctest import DocTestSuite
307
global MODULES_TO_TEST, MODULES_TO_DOCTEST
310
['bzrlib.selftest.MetaTestLog',
311
'bzrlib.selftest.testinv',
312
'bzrlib.selftest.versioning',
313
'bzrlib.selftest.testmerge3',
314
'bzrlib.selftest.testhashcache',
315
'bzrlib.selftest.teststatus',
316
'bzrlib.selftest.testlog',
317
'bzrlib.selftest.testrevisionnamespaces',
318
'bzrlib.selftest.testbranch',
319
'bzrlib.selftest.testrevision',
320
'bzrlib.selftest.test_merge_core',
321
'bzrlib.selftest.test_smart_add',
322
'bzrlib.selftest.testdiff',
323
'bzrlib.selftest.test_parent',
324
'bzrlib.selftest.test_xml',
325
'bzrlib.selftest.testfetch',
326
'bzrlib.selftest.whitebox',
327
'bzrlib.selftest.teststore',
328
'bzrlib.selftest.blackbox',
1042
global MODULES_TO_DOCTEST
1045
'bzrlib.tests.test_ancestry',
1046
'bzrlib.tests.test_api',
1047
'bzrlib.tests.test_bad_files',
1048
'bzrlib.tests.test_branch',
1049
'bzrlib.tests.test_bzrdir',
1050
'bzrlib.tests.test_command',
1051
'bzrlib.tests.test_commit',
1052
'bzrlib.tests.test_commit_merge',
1053
'bzrlib.tests.test_config',
1054
'bzrlib.tests.test_conflicts',
1055
'bzrlib.tests.test_decorators',
1056
'bzrlib.tests.test_diff',
1057
'bzrlib.tests.test_doc_generate',
1058
'bzrlib.tests.test_errors',
1059
'bzrlib.tests.test_escaped_store',
1060
'bzrlib.tests.test_fetch',
1061
'bzrlib.tests.test_gpg',
1062
'bzrlib.tests.test_graph',
1063
'bzrlib.tests.test_hashcache',
1064
'bzrlib.tests.test_http',
1065
'bzrlib.tests.test_identitymap',
1066
'bzrlib.tests.test_inv',
1067
'bzrlib.tests.test_knit',
1068
'bzrlib.tests.test_lockdir',
1069
'bzrlib.tests.test_lockable_files',
1070
'bzrlib.tests.test_log',
1071
'bzrlib.tests.test_merge',
1072
'bzrlib.tests.test_merge3',
1073
'bzrlib.tests.test_merge_core',
1074
'bzrlib.tests.test_missing',
1075
'bzrlib.tests.test_msgeditor',
1076
'bzrlib.tests.test_nonascii',
1077
'bzrlib.tests.test_options',
1078
'bzrlib.tests.test_osutils',
1079
'bzrlib.tests.test_patch',
1080
'bzrlib.tests.test_permissions',
1081
'bzrlib.tests.test_plugins',
1082
'bzrlib.tests.test_progress',
1083
'bzrlib.tests.test_reconcile',
1084
'bzrlib.tests.test_repository',
1085
'bzrlib.tests.test_revision',
1086
'bzrlib.tests.test_revisionnamespaces',
1087
'bzrlib.tests.test_revprops',
1088
'bzrlib.tests.test_rio',
1089
'bzrlib.tests.test_sampler',
1090
'bzrlib.tests.test_selftest',
1091
'bzrlib.tests.test_setup',
1092
'bzrlib.tests.test_sftp_transport',
1093
'bzrlib.tests.test_smart_add',
1094
'bzrlib.tests.test_source',
1095
'bzrlib.tests.test_store',
1096
'bzrlib.tests.test_symbol_versioning',
1097
'bzrlib.tests.test_testament',
1098
'bzrlib.tests.test_textfile',
1099
'bzrlib.tests.test_textmerge',
1100
'bzrlib.tests.test_trace',
1101
'bzrlib.tests.test_transactions',
1102
'bzrlib.tests.test_transform',
1103
'bzrlib.tests.test_transport',
1104
'bzrlib.tests.test_tsort',
1105
'bzrlib.tests.test_tuned_gzip',
1106
'bzrlib.tests.test_ui',
1107
'bzrlib.tests.test_upgrade',
1108
'bzrlib.tests.test_versionedfile',
1109
'bzrlib.tests.test_weave',
1110
'bzrlib.tests.test_whitebox',
1111
'bzrlib.tests.test_workingtree',
1112
'bzrlib.tests.test_xml',
331
for m in (bzrlib.store, bzrlib.inventory, bzrlib.branch,
332
bzrlib.osutils, bzrlib.commands, bzrlib.merge3):
333
if m not in MODULES_TO_DOCTEST:
334
MODULES_TO_DOCTEST.append(m)
336
TestCase.BZRPATH = os.path.join(os.path.realpath(os.path.dirname(bzrlib.__path__[0])), 'bzr')
337
print '%-30s %s' % ('bzr binary', TestCase.BZRPATH)
1114
test_transport_implementations = [
1115
'bzrlib.tests.test_transport_implementations']
1117
TestCase.BZRPATH = osutils.pathjoin(
1118
osutils.realpath(osutils.dirname(bzrlib.__path__[0])), 'bzr')
1119
print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
1120
print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
339
1122
suite = TestSuite()
340
suite.addTest(TestLoader().loadTestsFromNames(testmod_names))
1123
# python2.4's TestLoader.loadTestsFromNames gives very poor
1124
# errors if it fails to load a named module - no indication of what's
1125
# actually wrong, just "no such module". We should probably override that
1126
# class, but for the moment just load them ourselves. (mbp 20051202)
1127
loader = TestLoader()
1128
from bzrlib.transport import TransportTestProviderAdapter
1129
adapter = TransportTestProviderAdapter()
1130
adapt_modules(test_transport_implementations, adapter, loader, suite)
1131
for mod_name in testmod_names:
1132
mod = _load_module_by_name(mod_name)
1133
suite.addTest(loader.loadTestsFromModule(mod))
1134
for package in packages_to_test():
1135
suite.addTest(package.test_suite())
341
1136
for m in MODULES_TO_TEST:
342
suite.addTest(TestLoader().loadTestsFromModule(m))
1137
suite.addTest(loader.loadTestsFromModule(m))
343
1138
for m in (MODULES_TO_DOCTEST):
344
1139
suite.addTest(DocTestSuite(m))
345
for p in bzrlib.plugin.all_plugins:
346
if hasattr(p, 'test_suite'):
347
suite.addTest(p.test_suite())
1140
for name, plugin in bzrlib.plugin.all_plugins().items():
1141
if getattr(plugin, 'test_suite', None) is not None:
1142
suite.addTest(plugin.test_suite())
1146
def adapt_modules(mods_list, adapter, loader, suite):
1147
"""Adapt the modules in mods_list using adapter and add to suite."""
1148
for mod_name in mods_list:
1149
mod = _load_module_by_name(mod_name)
1150
for test in iter_suite_tests(loader.loadTestsFromModule(mod)):
1151
suite.addTests(adapter.adapt(test))
1154
def _load_module_by_name(mod_name):
1155
parts = mod_name.split('.')
1156
module = __import__(mod_name)
1158
# for historical reasons python returns the top-level module even though
1159
# it loads the submodule; we need to walk down to get the one we want.
1161
module = getattr(module, parts.pop(0))