1
# Copyright (C) 2005, 2006 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
# TODO: Perhaps there should be an API to find out if bzr running under the
19
# test suite -- some plugins might want to avoid making intrusive changes if
20
# this is the case. However, we want behaviour under to test to diverge as
21
# little as possible, so this should be used rarely if it's added at all.
22
# (Suggestion from j-a-meinel, 2005-11-24)
24
# NOTE: Some classes in here use camelCaseNaming() rather than
25
# underscore_naming(). That's for consistency with unittest; it's not the
26
# general style of bzrlib. Please continue that consistency when adding e.g.
27
# new assertFoo() methods.
30
from cStringIO import StringIO
39
from subprocess import Popen, PIPE
56
import bzrlib.commands
57
import bzrlib.bundle.serializer
59
import bzrlib.inventory
60
import bzrlib.iterablefile
65
# lsprof not available
67
from bzrlib.merge import merge_inner
71
from bzrlib.revision import common_ancestor
73
from bzrlib import symbol_versioning
75
from bzrlib.transport import get_transport
76
import bzrlib.transport
77
from bzrlib.transport.local import LocalURLServer
78
from bzrlib.transport.memory import MemoryServer
79
from bzrlib.transport.readonly import ReadonlyServer
80
from bzrlib.trace import mutter, note
81
from bzrlib.tests import TestUtil
82
from bzrlib.tests.HttpServer import HttpServer
83
from bzrlib.tests.TestUtil import (
87
from bzrlib.tests.treeshape import build_tree_contents
88
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
90
default_transport = LocalURLServer
93
MODULES_TO_DOCTEST = [
94
bzrlib.bundle.serializer,
106
def packages_to_test():
107
"""Return a list of packages to test.
109
The packages are not globally imported so that import failures are
110
triggered when running selftest, not when importing the command.
113
import bzrlib.tests.blackbox
114
import bzrlib.tests.branch_implementations
115
import bzrlib.tests.bzrdir_implementations
116
import bzrlib.tests.interrepository_implementations
117
import bzrlib.tests.interversionedfile_implementations
118
import bzrlib.tests.intertree_implementations
119
import bzrlib.tests.repository_implementations
120
import bzrlib.tests.revisionstore_implementations
121
import bzrlib.tests.tree_implementations
122
import bzrlib.tests.workingtree_implementations
125
bzrlib.tests.blackbox,
126
bzrlib.tests.branch_implementations,
127
bzrlib.tests.bzrdir_implementations,
128
bzrlib.tests.interrepository_implementations,
129
bzrlib.tests.interversionedfile_implementations,
130
bzrlib.tests.intertree_implementations,
131
bzrlib.tests.repository_implementations,
132
bzrlib.tests.revisionstore_implementations,
133
bzrlib.tests.tree_implementations,
134
bzrlib.tests.workingtree_implementations,
138
class ExtendedTestResult(unittest._TextTestResult):
139
"""Accepts, reports and accumulates the results of running tests.
141
Compared to this unittest version this class adds support for profiling,
142
benchmarking, stopping as soon as a test fails, and skipping tests.
143
There are further-specialized subclasses for different types of display.
148
def __init__(self, stream, descriptions, verbosity,
152
"""Construct new TestResult.
154
:param bench_history: Optionally, a writable file object to accumulate
157
unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
158
if bench_history is not None:
159
from bzrlib.version import _get_bzr_source_tree
160
src_tree = _get_bzr_source_tree()
163
revision_id = src_tree.get_parent_ids()[0]
165
# XXX: if this is a brand new tree, do the same as if there
169
# XXX: If there's no branch, what should we do?
171
bench_history.write("--date %s %s\n" % (time.time(), revision_id))
172
self._bench_history = bench_history
173
self.ui = bzrlib.ui.ui_factory
174
self.num_tests = num_tests
176
self.failure_count = 0
179
self._overall_start_time = time.time()
181
def extractBenchmarkTime(self, testCase):
182
"""Add a benchmark time for the current test case."""
183
self._benchmarkTime = getattr(testCase, "_benchtime", None)
185
def _elapsedTestTimeString(self):
186
"""Return a time string for the overall time the current test has taken."""
187
return self._formatTime(time.time() - self._start_time)
189
def _testTimeString(self):
190
if self._benchmarkTime is not None:
192
self._formatTime(self._benchmarkTime),
193
self._elapsedTestTimeString())
195
return " %s" % self._elapsedTestTimeString()
197
def _formatTime(self, seconds):
198
"""Format seconds as milliseconds with leading spaces."""
199
# some benchmarks can take thousands of seconds to run, so we need 8
201
return "%8dms" % (1000 * seconds)
203
def _shortened_test_description(self, test):
205
what = re.sub(r'^bzrlib\.(tests|benchmarks)\.', '', what)
208
def startTest(self, test):
209
unittest.TestResult.startTest(self, test)
210
self.report_test_start(test)
211
self._recordTestStartTime()
213
def _recordTestStartTime(self):
214
"""Record that a test has started."""
215
self._start_time = time.time()
217
def addError(self, test, err):
218
if isinstance(err[1], TestSkipped):
219
return self.addSkipped(test, err)
220
unittest.TestResult.addError(self, test, err)
221
# We can only do this if we have one of our TestCases, not if
223
setKeepLogfile = getattr(test, 'setKeepLogfile', None)
224
if setKeepLogfile is not None:
226
self.extractBenchmarkTime(test)
227
self.report_error(test, err)
231
def addFailure(self, test, err):
232
unittest.TestResult.addFailure(self, test, err)
233
# We can only do this if we have one of our TestCases, not if
235
setKeepLogfile = getattr(test, 'setKeepLogfile', None)
236
if setKeepLogfile is not None:
238
self.extractBenchmarkTime(test)
239
self.report_failure(test, err)
243
def addSuccess(self, test):
244
self.extractBenchmarkTime(test)
245
if self._bench_history is not None:
246
if self._benchmarkTime is not None:
247
self._bench_history.write("%s %s\n" % (
248
self._formatTime(self._benchmarkTime),
250
self.report_success(test)
251
unittest.TestResult.addSuccess(self, test)
253
def addSkipped(self, test, skip_excinfo):
254
self.extractBenchmarkTime(test)
255
self.report_skip(test, skip_excinfo)
256
# seems best to treat this as success from point-of-view of unittest
257
# -- it actually does nothing so it barely matters :)
260
except KeyboardInterrupt:
263
self.addError(test, test.__exc_info())
265
unittest.TestResult.addSuccess(self, test)
267
def printErrorList(self, flavour, errors):
268
for test, err in errors:
269
self.stream.writeln(self.separator1)
270
self.stream.writeln("%s: %s" % (flavour, self.getDescription(test)))
271
if getattr(test, '_get_log', None) is not None:
273
print >>self.stream, \
274
('vvvv[log from %s]' % test.id()).ljust(78,'-')
275
print >>self.stream, test._get_log()
276
print >>self.stream, \
277
('^^^^[log from %s]' % test.id()).ljust(78,'-')
278
self.stream.writeln(self.separator2)
279
self.stream.writeln("%s" % err)
284
def report_cleaning_up(self):
287
def report_success(self, test):
291
class TextTestResult(ExtendedTestResult):
292
"""Displays progress and results of tests in text form"""
294
def __init__(self, *args, **kw):
295
ExtendedTestResult.__init__(self, *args, **kw)
296
self.pb = self.ui.nested_progress_bar()
297
self.pb.show_pct = False
298
self.pb.show_spinner = False
299
self.pb.show_eta = False,
300
self.pb.show_count = False
301
self.pb.show_bar = False
303
def report_starting(self):
304
self.pb.update('[test 0/%d] starting...' % (self.num_tests))
306
def _progress_prefix_text(self):
307
a = '[%d' % self.count
308
if self.num_tests is not None:
309
a +='/%d' % self.num_tests
310
a += ' in %ds' % (time.time() - self._overall_start_time)
312
a += ', %d errors' % self.error_count
313
if self.failure_count:
314
a += ', %d failed' % self.failure_count
316
a += ', %d skipped' % self.skip_count
320
def report_test_start(self, test):
323
self._progress_prefix_text()
325
+ self._shortened_test_description(test))
327
def report_error(self, test, err):
328
self.error_count += 1
329
self.pb.note('ERROR: %s\n %s\n',
330
self._shortened_test_description(test),
334
def report_failure(self, test, err):
335
self.failure_count += 1
336
self.pb.note('FAIL: %s\n %s\n',
337
self._shortened_test_description(test),
341
def report_skip(self, test, skip_excinfo):
344
# at the moment these are mostly not things we can fix
345
# and so they just produce stipple; use the verbose reporter
348
# show test and reason for skip
349
self.pb.note('SKIP: %s\n %s\n',
350
self._shortened_test_description(test),
353
# since the class name was left behind in the still-visible
355
self.pb.note('SKIP: %s', skip_excinfo[1])
357
def report_cleaning_up(self):
358
self.pb.update('cleaning up...')
364
class VerboseTestResult(ExtendedTestResult):
365
"""Produce long output, with one line per test run plus times"""
367
def _ellipsize_to_right(self, a_string, final_width):
368
"""Truncate and pad a string, keeping the right hand side"""
369
if len(a_string) > final_width:
370
result = '...' + a_string[3-final_width:]
373
return result.ljust(final_width)
375
def report_starting(self):
376
self.stream.write('running %d tests...\n' % self.num_tests)
378
def report_test_start(self, test):
380
name = self._shortened_test_description(test)
381
# width needs space for 6 char status, plus 1 for slash, plus 2 10-char
382
# numbers, plus a trailing blank
383
self.stream.write(self._ellipsize_to_right(name,
384
osutils.terminal_width()-30))
387
def report_error(self, test, err):
388
self.error_count += 1
389
self.stream.writeln('ERROR %s\n %s'
390
% (self._testTimeString(), err[1]))
392
def report_failure(self, test, err):
393
self.failure_count += 1
394
self.stream.writeln(' FAIL %s\n %s'
395
% (self._testTimeString(), err[1]))
397
def report_success(self, test):
398
self.stream.writeln(' OK %s' % self._testTimeString())
399
for bench_called, stats in getattr(test, '_benchcalls', []):
400
self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
401
stats.pprint(file=self.stream)
404
def report_skip(self, test, skip_excinfo):
405
print >>self.stream, ' SKIP %s' % self._testTimeString()
406
print >>self.stream, ' %s' % skip_excinfo[1]
409
class TextTestRunner(object):
410
stop_on_failure = False
418
self.stream = unittest._WritelnDecorator(stream)
419
self.descriptions = descriptions
420
self.verbosity = verbosity
421
self.keep_output = keep_output
422
self._bench_history = bench_history
425
"Run the given test case or test suite."
426
startTime = time.time()
427
if self.verbosity == 1:
428
result_class = TextTestResult
429
elif self.verbosity >= 2:
430
result_class = VerboseTestResult
431
result = result_class(self.stream,
434
bench_history=self._bench_history,
435
num_tests=test.countTestCases(),
437
result.stop_early = self.stop_on_failure
438
result.report_starting()
440
stopTime = time.time()
441
timeTaken = stopTime - startTime
443
self.stream.writeln(result.separator2)
444
run = result.testsRun
445
self.stream.writeln("Ran %d test%s in %.3fs" %
446
(run, run != 1 and "s" or "", timeTaken))
447
self.stream.writeln()
448
if not result.wasSuccessful():
449
self.stream.write("FAILED (")
450
failed, errored = map(len, (result.failures, result.errors))
452
self.stream.write("failures=%d" % failed)
454
if failed: self.stream.write(", ")
455
self.stream.write("errors=%d" % errored)
456
self.stream.writeln(")")
458
self.stream.writeln("OK")
459
result.report_cleaning_up()
460
# This is still a little bogus,
461
# but only a little. Folk not using our testrunner will
462
# have to delete their temp directories themselves.
463
test_root = TestCaseWithMemoryTransport.TEST_ROOT
464
if result.wasSuccessful() or not self.keep_output:
465
if test_root is not None:
466
# If LANG=C we probably have created some bogus paths
467
# which rmtree(unicode) will fail to delete
468
# so make sure we are using rmtree(str) to delete everything
469
# except on win32, where rmtree(str) will fail
470
# since it doesn't have the property of byte-stream paths
471
# (they are either ascii or mbcs)
472
if sys.platform == 'win32':
473
# make sure we are using the unicode win32 api
474
test_root = unicode(test_root)
476
test_root = test_root.encode(
477
sys.getfilesystemencoding())
478
osutils.rmtree(test_root)
480
note("Failed tests working directories are in '%s'\n", test_root)
481
TestCaseWithMemoryTransport.TEST_ROOT = None
486
def iter_suite_tests(suite):
487
"""Return all tests in a suite, recursing through nested suites"""
488
for item in suite._tests:
489
if isinstance(item, unittest.TestCase):
491
elif isinstance(item, unittest.TestSuite):
492
for r in iter_suite_tests(item):
495
raise Exception('unknown object %r inside test suite %r'
499
class TestSkipped(Exception):
500
"""Indicates that a test was intentionally skipped, rather than failing."""
503
class CommandFailed(Exception):
507
class StringIOWrapper(object):
508
"""A wrapper around cStringIO which just adds an encoding attribute.
510
Internally we can check sys.stdout to see what the output encoding
511
should be. However, cStringIO has no encoding attribute that we can
512
set. So we wrap it instead.
517
def __init__(self, s=None):
519
self.__dict__['_cstring'] = StringIO(s)
521
self.__dict__['_cstring'] = StringIO()
523
def __getattr__(self, name, getattr=getattr):
524
return getattr(self.__dict__['_cstring'], name)
526
def __setattr__(self, name, val):
527
if name == 'encoding':
528
self.__dict__['encoding'] = val
530
return setattr(self._cstring, name, val)
533
class TestCase(unittest.TestCase):
534
"""Base class for bzr unit tests.
536
Tests that need access to disk resources should subclass
537
TestCaseInTempDir not TestCase.
539
Error and debug log messages are redirected from their usual
540
location into a temporary file, the contents of which can be
541
retrieved by _get_log(). We use a real OS file, not an in-memory object,
542
so that it can also capture file IO. When the test completes this file
543
is read into memory and removed from disk.
545
There are also convenience functions to invoke bzr's command-line
546
routine, and to build and check bzr trees.
548
In addition to the usual method of overriding tearDown(), this class also
549
allows subclasses to register functions into the _cleanups list, which is
550
run in order as the object is torn down. It's less likely this will be
551
accidentally overlooked.
554
_log_file_name = None
556
_keep_log_file = False
557
# record lsprof data when performing benchmark calls.
558
_gather_lsprof_in_benchmarks = False
560
def __init__(self, methodName='testMethod'):
561
super(TestCase, self).__init__(methodName)
565
unittest.TestCase.setUp(self)
566
self._cleanEnvironment()
567
bzrlib.trace.disable_default_logging()
570
self._benchcalls = []
571
self._benchtime = None
572
# prevent hooks affecting tests
573
self._preserved_hooks = bzrlib.branch.Branch.hooks
574
self.addCleanup(self._restoreHooks)
575
# this list of hooks must be kept in sync with the defaults
577
bzrlib.branch.Branch.hooks = bzrlib.branch.BranchHooks()
579
def _silenceUI(self):
580
"""Turn off UI for duration of test"""
581
# by default the UI is off; tests can turn it on if they want it.
582
saved = bzrlib.ui.ui_factory
584
bzrlib.ui.ui_factory = saved
585
bzrlib.ui.ui_factory = bzrlib.ui.SilentUIFactory()
586
self.addCleanup(_restore)
588
def _ndiff_strings(self, a, b):
589
"""Return ndiff between two strings containing lines.
591
A trailing newline is added if missing to make the strings
593
if b and b[-1] != '\n':
595
if a and a[-1] != '\n':
597
difflines = difflib.ndiff(a.splitlines(True),
599
linejunk=lambda x: False,
600
charjunk=lambda x: False)
601
return ''.join(difflines)
603
def assertEqualDiff(self, a, b, message=None):
604
"""Assert two texts are equal, if not raise an exception.
606
This is intended for use with multi-line strings where it can
607
be hard to find the differences by eye.
609
# TODO: perhaps override assertEquals to call this for strings?
613
message = "texts not equal:\n"
614
raise AssertionError(message +
615
self._ndiff_strings(a, b))
617
def assertEqualMode(self, mode, mode_test):
618
self.assertEqual(mode, mode_test,
619
'mode mismatch %o != %o' % (mode, mode_test))
621
def assertStartsWith(self, s, prefix):
622
if not s.startswith(prefix):
623
raise AssertionError('string %r does not start with %r' % (s, prefix))
625
def assertEndsWith(self, s, suffix):
626
"""Asserts that s ends with suffix."""
627
if not s.endswith(suffix):
628
raise AssertionError('string %r does not end with %r' % (s, suffix))
630
def assertContainsRe(self, haystack, needle_re):
631
"""Assert that a contains something matching a regular expression."""
632
if not re.search(needle_re, haystack):
633
raise AssertionError('pattern "%s" not found in "%s"'
634
% (needle_re, haystack))
636
def assertNotContainsRe(self, haystack, needle_re):
637
"""Assert that a does not match a regular expression"""
638
if re.search(needle_re, haystack):
639
raise AssertionError('pattern "%s" found in "%s"'
640
% (needle_re, haystack))
642
def assertSubset(self, sublist, superlist):
643
"""Assert that every entry in sublist is present in superlist."""
645
for entry in sublist:
646
if entry not in superlist:
647
missing.append(entry)
649
raise AssertionError("value(s) %r not present in container %r" %
650
(missing, superlist))
652
def assertListRaises(self, excClass, func, *args, **kwargs):
653
"""Fail unless excClass is raised when the iterator from func is used.
655
Many functions can return generators this makes sure
656
to wrap them in a list() call to make sure the whole generator
657
is run, and that the proper exception is raised.
660
list(func(*args, **kwargs))
664
if getattr(excClass,'__name__', None) is not None:
665
excName = excClass.__name__
667
excName = str(excClass)
668
raise self.failureException, "%s not raised" % excName
670
def assertIs(self, left, right, message=None):
671
if not (left is right):
672
if message is not None:
673
raise AssertionError(message)
675
raise AssertionError("%r is not %r." % (left, right))
677
def assertIsNot(self, left, right, message=None):
679
if message is not None:
680
raise AssertionError(message)
682
raise AssertionError("%r is %r." % (left, right))
684
def assertTransportMode(self, transport, path, mode):
685
"""Fail if a path does not have mode mode.
687
If modes are not supported on this transport, the assertion is ignored.
689
if not transport._can_roundtrip_unix_modebits():
691
path_stat = transport.stat(path)
692
actual_mode = stat.S_IMODE(path_stat.st_mode)
693
self.assertEqual(mode, actual_mode,
694
'mode of %r incorrect (%o != %o)' % (path, mode, actual_mode))
696
def assertIsInstance(self, obj, kls):
697
"""Fail if obj is not an instance of kls"""
698
if not isinstance(obj, kls):
699
self.fail("%r is an instance of %s rather than %s" % (
700
obj, obj.__class__, kls))
702
def _capture_warnings(self, a_callable, *args, **kwargs):
703
"""A helper for callDeprecated and applyDeprecated.
705
:param a_callable: A callable to call.
706
:param args: The positional arguments for the callable
707
:param kwargs: The keyword arguments for the callable
708
:return: A tuple (warnings, result). result is the result of calling
709
a_callable(*args, **kwargs).
712
def capture_warnings(msg, cls=None, stacklevel=None):
713
# we've hooked into a deprecation specific callpath,
714
# only deprecations should getting sent via it.
715
self.assertEqual(cls, DeprecationWarning)
716
local_warnings.append(msg)
717
original_warning_method = symbol_versioning.warn
718
symbol_versioning.set_warning_method(capture_warnings)
720
result = a_callable(*args, **kwargs)
722
symbol_versioning.set_warning_method(original_warning_method)
723
return (local_warnings, result)
725
def applyDeprecated(self, deprecation_format, a_callable, *args, **kwargs):
726
"""Call a deprecated callable without warning the user.
728
:param deprecation_format: The deprecation format that the callable
729
should have been deprecated with. This is the same type as the
730
parameter to deprecated_method/deprecated_function. If the
731
callable is not deprecated with this format, an assertion error
733
:param a_callable: A callable to call. This may be a bound method or
734
a regular function. It will be called with *args and **kwargs.
735
:param args: The positional arguments for the callable
736
:param kwargs: The keyword arguments for the callable
737
:return: The result of a_callable(*args, **kwargs)
739
call_warnings, result = self._capture_warnings(a_callable,
741
expected_first_warning = symbol_versioning.deprecation_string(
742
a_callable, deprecation_format)
743
if len(call_warnings) == 0:
744
self.fail("No assertion generated by call to %s" %
746
self.assertEqual(expected_first_warning, call_warnings[0])
749
def callDeprecated(self, expected, callable, *args, **kwargs):
750
"""Assert that a callable is deprecated in a particular way.
752
This is a very precise test for unusual requirements. The
753
applyDeprecated helper function is probably more suited for most tests
754
as it allows you to simply specify the deprecation format being used
755
and will ensure that that is issued for the function being called.
757
:param expected: a list of the deprecation warnings expected, in order
758
:param callable: The callable to call
759
:param args: The positional arguments for the callable
760
:param kwargs: The keyword arguments for the callable
762
call_warnings, result = self._capture_warnings(callable,
764
self.assertEqual(expected, call_warnings)
767
def _startLogFile(self):
768
"""Send bzr and test log messages to a temporary file.
770
The file is removed as the test is torn down.
772
fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
773
self._log_file = os.fdopen(fileno, 'w+')
774
self._log_nonce = bzrlib.trace.enable_test_log(self._log_file)
775
self._log_file_name = name
776
self.addCleanup(self._finishLogFile)
778
def _finishLogFile(self):
779
"""Finished with the log file.
781
Close the file and delete it, unless setKeepLogfile was called.
783
if self._log_file is None:
785
bzrlib.trace.disable_test_log(self._log_nonce)
786
self._log_file.close()
787
self._log_file = None
788
if not self._keep_log_file:
789
os.remove(self._log_file_name)
790
self._log_file_name = None
792
def setKeepLogfile(self):
793
"""Make the logfile not be deleted when _finishLogFile is called."""
794
self._keep_log_file = True
796
def addCleanup(self, callable):
797
"""Arrange to run a callable when this case is torn down.
799
Callables are run in the reverse of the order they are registered,
800
ie last-in first-out.
802
if callable in self._cleanups:
803
raise ValueError("cleanup function %r already registered on %s"
805
self._cleanups.append(callable)
807
def _cleanEnvironment(self):
809
'BZR_HOME': None, # Don't inherit BZR_HOME to all the tests.
811
'APPDATA': os.getcwd(),
813
'BZREMAIL': None, # may still be present in the environment
815
'BZR_PROGRESS_BAR': None,
825
# Nobody cares about these ones AFAIK. So far at
826
# least. If you do (care), please update this comment
832
self.addCleanup(self._restoreEnvironment)
833
for name, value in new_env.iteritems():
834
self._captureVar(name, value)
836
def _captureVar(self, name, newvalue):
837
"""Set an environment variable, and reset it when finished."""
838
self.__old_env[name] = osutils.set_or_unset_env(name, newvalue)
840
def _restoreEnvironment(self):
841
for name, value in self.__old_env.iteritems():
842
osutils.set_or_unset_env(name, value)
844
def _restoreHooks(self):
845
bzrlib.branch.Branch.hooks = self._preserved_hooks
849
unittest.TestCase.tearDown(self)
851
def time(self, callable, *args, **kwargs):
852
"""Run callable and accrue the time it takes to the benchmark time.
854
If lsprofiling is enabled (i.e. by --lsprof-time to bzr selftest) then
855
this will cause lsprofile statistics to be gathered and stored in
858
if self._benchtime is None:
862
if not self._gather_lsprof_in_benchmarks:
863
return callable(*args, **kwargs)
865
# record this benchmark
866
ret, stats = bzrlib.lsprof.profile(callable, *args, **kwargs)
868
self._benchcalls.append(((callable, args, kwargs), stats))
871
self._benchtime += time.time() - start
873
def _runCleanups(self):
874
"""Run registered cleanup functions.
876
This should only be called from TestCase.tearDown.
878
# TODO: Perhaps this should keep running cleanups even if
880
for cleanup_fn in reversed(self._cleanups):
883
def log(self, *args):
886
def _get_log(self, keep_log_file=False):
887
"""Return as a string the log for this test. If the file is still
888
on disk and keep_log_file=False, delete the log file and store the
889
content in self._log_contents."""
890
# flush the log file, to get all content
892
bzrlib.trace._trace_file.flush()
893
if self._log_contents:
894
return self._log_contents
895
if self._log_file_name is not None:
896
logfile = open(self._log_file_name)
898
log_contents = logfile.read()
901
if not keep_log_file:
902
self._log_contents = log_contents
903
os.remove(self._log_file_name)
906
return "DELETED log file to reduce memory footprint"
908
def capture(self, cmd, retcode=0):
909
"""Shortcut that splits cmd into words, runs, and returns stdout"""
910
return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
912
def run_bzr_captured(self, argv, retcode=0, encoding=None, stdin=None,
914
"""Invoke bzr and return (stdout, stderr).
916
Useful for code that wants to check the contents of the
917
output, the way error messages are presented, etc.
919
This should be the main method for tests that want to exercise the
920
overall behavior of the bzr application (rather than a unit test
921
or a functional test of the library.)
923
Much of the old code runs bzr by forking a new copy of Python, but
924
that is slower, harder to debug, and generally not necessary.
926
This runs bzr through the interface that catches and reports
927
errors, and with logging set to something approximating the
928
default, so that error reporting can be checked.
930
:param argv: arguments to invoke bzr
931
:param retcode: expected return code, or None for don't-care.
932
:param encoding: encoding for sys.stdout and sys.stderr
933
:param stdin: A string to be used as stdin for the command.
934
:param working_dir: Change to this directory before running
937
encoding = bzrlib.user_encoding
938
if stdin is not None:
939
stdin = StringIO(stdin)
940
stdout = StringIOWrapper()
941
stderr = StringIOWrapper()
942
stdout.encoding = encoding
943
stderr.encoding = encoding
945
self.log('run bzr: %r', argv)
946
# FIXME: don't call into logging here
947
handler = logging.StreamHandler(stderr)
948
handler.setLevel(logging.INFO)
949
logger = logging.getLogger('')
950
logger.addHandler(handler)
951
old_ui_factory = bzrlib.ui.ui_factory
952
bzrlib.ui.ui_factory = bzrlib.tests.blackbox.TestUIFactory(
955
bzrlib.ui.ui_factory.stdin = stdin
958
if working_dir is not None:
959
cwd = osutils.getcwd()
960
os.chdir(working_dir)
963
saved_debug_flags = frozenset(debug.debug_flags)
964
debug.debug_flags.clear()
966
result = self.apply_redirected(stdin, stdout, stderr,
967
bzrlib.commands.run_bzr_catch_errors,
970
debug.debug_flags.update(saved_debug_flags)
972
logger.removeHandler(handler)
973
bzrlib.ui.ui_factory = old_ui_factory
977
out = stdout.getvalue()
978
err = stderr.getvalue()
980
self.log('output:\n%r', out)
982
self.log('errors:\n%r', err)
983
if retcode is not None:
984
self.assertEquals(retcode, result)
987
def run_bzr(self, *args, **kwargs):
988
"""Invoke bzr, as if it were run from the command line.
990
This should be the main method for tests that want to exercise the
991
overall behavior of the bzr application (rather than a unit test
992
or a functional test of the library.)
994
This sends the stdout/stderr results into the test's log,
995
where it may be useful for debugging. See also run_captured.
997
:param stdin: A string to be used as stdin for the command.
999
retcode = kwargs.pop('retcode', 0)
1000
encoding = kwargs.pop('encoding', None)
1001
stdin = kwargs.pop('stdin', None)
1002
working_dir = kwargs.pop('working_dir', None)
1003
return self.run_bzr_captured(args, retcode=retcode, encoding=encoding,
1004
stdin=stdin, working_dir=working_dir)
1006
def run_bzr_decode(self, *args, **kwargs):
1007
if 'encoding' in kwargs:
1008
encoding = kwargs['encoding']
1010
encoding = bzrlib.user_encoding
1011
return self.run_bzr(*args, **kwargs)[0].decode(encoding)
1013
def run_bzr_error(self, error_regexes, *args, **kwargs):
1014
"""Run bzr, and check that stderr contains the supplied regexes
1016
:param error_regexes: Sequence of regular expressions which
1017
must each be found in the error output. The relative ordering
1019
:param args: command-line arguments for bzr
1020
:param kwargs: Keyword arguments which are interpreted by run_bzr
1021
This function changes the default value of retcode to be 3,
1022
since in most cases this is run when you expect bzr to fail.
1023
:return: (out, err) The actual output of running the command (in case you
1024
want to do more inspection)
1027
# Make sure that commit is failing because there is nothing to do
1028
self.run_bzr_error(['no changes to commit'],
1029
'commit', '-m', 'my commit comment')
1030
# Make sure --strict is handling an unknown file, rather than
1031
# giving us the 'nothing to do' error
1032
self.build_tree(['unknown'])
1033
self.run_bzr_error(['Commit refused because there are unknown files'],
1034
'commit', '--strict', '-m', 'my commit comment')
1036
kwargs.setdefault('retcode', 3)
1037
out, err = self.run_bzr(*args, **kwargs)
1038
for regex in error_regexes:
1039
self.assertContainsRe(err, regex)
1042
def run_bzr_subprocess(self, *args, **kwargs):
1043
"""Run bzr in a subprocess for testing.
1045
This starts a new Python interpreter and runs bzr in there.
1046
This should only be used for tests that have a justifiable need for
1047
this isolation: e.g. they are testing startup time, or signal
1048
handling, or early startup code, etc. Subprocess code can't be
1049
profiled or debugged so easily.
1051
:param retcode: The status code that is expected. Defaults to 0. If
1052
None is supplied, the status code is not checked.
1053
:param env_changes: A dictionary which lists changes to environment
1054
variables. A value of None will unset the env variable.
1055
The values must be strings. The change will only occur in the
1056
child, so you don't need to fix the environment after running.
1057
:param universal_newlines: Convert CRLF => LF
1058
:param allow_plugins: By default the subprocess is run with
1059
--no-plugins to ensure test reproducibility. Also, it is possible
1060
for system-wide plugins to create unexpected output on stderr,
1061
which can cause unnecessary test failures.
1063
env_changes = kwargs.get('env_changes', {})
1064
working_dir = kwargs.get('working_dir', None)
1065
allow_plugins = kwargs.get('allow_plugins', False)
1066
process = self.start_bzr_subprocess(args, env_changes=env_changes,
1067
working_dir=working_dir,
1068
allow_plugins=allow_plugins)
1069
# We distinguish between retcode=None and retcode not passed.
1070
supplied_retcode = kwargs.get('retcode', 0)
1071
return self.finish_bzr_subprocess(process, retcode=supplied_retcode,
1072
universal_newlines=kwargs.get('universal_newlines', False),
1075
def start_bzr_subprocess(self, process_args, env_changes=None,
1076
skip_if_plan_to_signal=False,
1078
allow_plugins=False):
1079
"""Start bzr in a subprocess for testing.
1081
This starts a new Python interpreter and runs bzr in there.
1082
This should only be used for tests that have a justifiable need for
1083
this isolation: e.g. they are testing startup time, or signal
1084
handling, or early startup code, etc. Subprocess code can't be
1085
profiled or debugged so easily.
1087
:param process_args: a list of arguments to pass to the bzr executable,
1088
for example `['--version']`.
1089
:param env_changes: A dictionary which lists changes to environment
1090
variables. A value of None will unset the env variable.
1091
The values must be strings. The change will only occur in the
1092
child, so you don't need to fix the environment after running.
1093
:param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
1095
:param allow_plugins: If False (default) pass --no-plugins to bzr.
1097
:returns: Popen object for the started process.
1099
if skip_if_plan_to_signal:
1100
if not getattr(os, 'kill', None):
1101
raise TestSkipped("os.kill not available.")
1103
if env_changes is None:
1107
def cleanup_environment():
1108
for env_var, value in env_changes.iteritems():
1109
old_env[env_var] = osutils.set_or_unset_env(env_var, value)
1111
def restore_environment():
1112
for env_var, value in old_env.iteritems():
1113
osutils.set_or_unset_env(env_var, value)
1115
bzr_path = self.get_bzr_path()
1118
if working_dir is not None:
1119
cwd = osutils.getcwd()
1120
os.chdir(working_dir)
1123
# win32 subprocess doesn't support preexec_fn
1124
# so we will avoid using it on all platforms, just to
1125
# make sure the code path is used, and we don't break on win32
1126
cleanup_environment()
1127
command = [sys.executable, bzr_path]
1128
if not allow_plugins:
1129
command.append('--no-plugins')
1130
command.extend(process_args)
1131
process = self._popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE)
1133
restore_environment()
1139
def _popen(self, *args, **kwargs):
1140
"""Place a call to Popen.
1142
Allows tests to override this method to intercept the calls made to
1143
Popen for introspection.
1145
return Popen(*args, **kwargs)
1147
def get_bzr_path(self):
1148
"""Return the path of the 'bzr' executable for this test suite."""
1149
bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
1150
if not os.path.isfile(bzr_path):
1151
# We are probably installed. Assume sys.argv is the right file
1152
bzr_path = sys.argv[0]
1155
def finish_bzr_subprocess(self, process, retcode=0, send_signal=None,
1156
universal_newlines=False, process_args=None):
1157
"""Finish the execution of process.
1159
:param process: the Popen object returned from start_bzr_subprocess.
1160
:param retcode: The status code that is expected. Defaults to 0. If
1161
None is supplied, the status code is not checked.
1162
:param send_signal: an optional signal to send to the process.
1163
:param universal_newlines: Convert CRLF => LF
1164
:returns: (stdout, stderr)
1166
if send_signal is not None:
1167
os.kill(process.pid, send_signal)
1168
out, err = process.communicate()
1170
if universal_newlines:
1171
out = out.replace('\r\n', '\n')
1172
err = err.replace('\r\n', '\n')
1174
if retcode is not None and retcode != process.returncode:
1175
if process_args is None:
1176
process_args = "(unknown args)"
1177
mutter('Output of bzr %s:\n%s', process_args, out)
1178
mutter('Error for bzr %s:\n%s', process_args, err)
1179
self.fail('Command bzr %s failed with retcode %s != %s'
1180
% (process_args, retcode, process.returncode))
1183
def check_inventory_shape(self, inv, shape):
1184
"""Compare an inventory to a list of expected names.
1186
Fail if they are not precisely equal.
1189
shape = list(shape) # copy
1190
for path, ie in inv.entries():
1191
name = path.replace('\\', '/')
1192
if ie.kind == 'dir':
1199
self.fail("expected paths not found in inventory: %r" % shape)
1201
self.fail("unexpected paths found in inventory: %r" % extras)
1203
def apply_redirected(self, stdin=None, stdout=None, stderr=None,
1204
a_callable=None, *args, **kwargs):
1205
"""Call callable with redirected std io pipes.
1207
Returns the return code."""
1208
if not callable(a_callable):
1209
raise ValueError("a_callable must be callable.")
1211
stdin = StringIO("")
1213
if getattr(self, "_log_file", None) is not None:
1214
stdout = self._log_file
1218
if getattr(self, "_log_file", None is not None):
1219
stderr = self._log_file
1222
real_stdin = sys.stdin
1223
real_stdout = sys.stdout
1224
real_stderr = sys.stderr
1229
return a_callable(*args, **kwargs)
1231
sys.stdout = real_stdout
1232
sys.stderr = real_stderr
1233
sys.stdin = real_stdin
1235
@symbol_versioning.deprecated_method(symbol_versioning.zero_eleven)
1236
def merge(self, branch_from, wt_to):
1237
"""A helper for tests to do a ui-less merge.
1239
This should move to the main library when someone has time to integrate
1242
# minimal ui-less merge.
1243
wt_to.branch.fetch(branch_from)
1244
base_rev = common_ancestor(branch_from.last_revision(),
1245
wt_to.branch.last_revision(),
1246
wt_to.branch.repository)
1247
merge_inner(wt_to.branch, branch_from.basis_tree(),
1248
wt_to.branch.repository.revision_tree(base_rev),
1250
wt_to.add_parent_tree_id(branch_from.last_revision())
1252
def reduceLockdirTimeout(self):
1253
"""Reduce the default lock timeout for the duration of the test, so that
1254
if LockContention occurs during a test, it does so quickly.
1256
Tests that expect to provoke LockContention errors should call this.
1258
orig_timeout = bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS
1260
bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS = orig_timeout
1261
self.addCleanup(resetTimeout)
1262
bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS = 0
1264
BzrTestBase = TestCase
1267
class TestCaseWithMemoryTransport(TestCase):
1268
"""Common test class for tests that do not need disk resources.
1270
Tests that need disk resources should derive from TestCaseWithTransport.
1272
TestCaseWithMemoryTransport sets the TEST_ROOT variable for all bzr tests.
1274
For TestCaseWithMemoryTransport the test_home_dir is set to the name of
1275
a directory which does not exist. This serves to help ensure test isolation
1276
is preserved. test_dir is set to the TEST_ROOT, as is cwd, because they
1277
must exist. However, TestCaseWithMemoryTransport does not offer local
1278
file defaults for the transport in tests, nor does it obey the command line
1279
override, so tests that accidentally write to the common directory should
1287
def __init__(self, methodName='runTest'):
1288
# allow test parameterisation after test construction and before test
1289
# execution. Variables that the parameteriser sets need to be
1290
# ones that are not set by setUp, or setUp will trash them.
1291
super(TestCaseWithMemoryTransport, self).__init__(methodName)
1292
self.vfs_transport_factory = default_transport
1293
self.transport_server = None
1294
self.transport_readonly_server = None
1295
self.__vfs_server = None
1297
def get_transport(self):
1298
"""Return a writeable transport for the test scratch space"""
1299
t = get_transport(self.get_url())
1300
self.assertFalse(t.is_readonly())
1303
def get_readonly_transport(self):
1304
"""Return a readonly transport for the test scratch space
1306
This can be used to test that operations which should only need
1307
readonly access in fact do not try to write.
1309
t = get_transport(self.get_readonly_url())
1310
self.assertTrue(t.is_readonly())
1313
def create_transport_readonly_server(self):
1314
"""Create a transport server from class defined at init.
1316
This is mostly a hook for daughter classes.
1318
return self.transport_readonly_server()
1320
def get_readonly_server(self):
1321
"""Get the server instance for the readonly transport
1323
This is useful for some tests with specific servers to do diagnostics.
1325
if self.__readonly_server is None:
1326
if self.transport_readonly_server is None:
1327
# readonly decorator requested
1328
# bring up the server
1329
self.__readonly_server = ReadonlyServer()
1330
self.__readonly_server.setUp(self.get_vfs_only_server())
1332
self.__readonly_server = self.create_transport_readonly_server()
1333
self.__readonly_server.setUp(self.get_vfs_only_server())
1334
self.addCleanup(self.__readonly_server.tearDown)
1335
return self.__readonly_server
1337
def get_readonly_url(self, relpath=None):
1338
"""Get a URL for the readonly transport.
1340
This will either be backed by '.' or a decorator to the transport
1341
used by self.get_url()
1342
relpath provides for clients to get a path relative to the base url.
1343
These should only be downwards relative, not upwards.
1345
base = self.get_readonly_server().get_url()
1346
if relpath is not None:
1347
if not base.endswith('/'):
1349
base = base + relpath
1352
def get_vfs_only_server(self):
1353
"""Get the vfs only read/write server instance.
1355
This is useful for some tests with specific servers that need
1358
For TestCaseWithMemoryTransport this is always a MemoryServer, and there
1359
is no means to override it.
1361
if self.__vfs_server is None:
1362
self.__vfs_server = MemoryServer()
1363
self.__vfs_server.setUp()
1364
self.addCleanup(self.__vfs_server.tearDown)
1365
return self.__vfs_server
1367
def get_server(self):
1368
"""Get the read/write server instance.
1370
This is useful for some tests with specific servers that need
1373
This is built from the self.transport_server factory. If that is None,
1374
then the self.get_vfs_server is returned.
1376
if self.__server is None:
1377
if self.transport_server is None:
1378
return self.get_vfs_only_server()
1380
# bring up a decorated means of access to the vfs only server.
1381
self.__server = self.transport_server()
1382
self.__server.setUp(self.get_vfs_only_server())
1383
self.addCleanup(self.__server.tearDown)
1384
return self.__server
1386
def _adjust_url(self, base, relpath):
1387
"""Get a URL (or maybe a path) for the readwrite transport.
1389
This will either be backed by '.' or to an equivalent non-file based
1391
relpath provides for clients to get a path relative to the base url.
1392
These should only be downwards relative, not upwards.
1394
if relpath is not None and relpath != '.':
1395
if not base.endswith('/'):
1397
# XXX: Really base should be a url; we did after all call
1398
# get_url()! But sometimes it's just a path (from
1399
# LocalAbspathServer), and it'd be wrong to append urlescaped data
1400
# to a non-escaped local path.
1401
if base.startswith('./') or base.startswith('/'):
1404
base += urlutils.escape(relpath)
1407
def get_url(self, relpath=None):
1408
"""Get a URL (or maybe a path) for the readwrite transport.
1410
This will either be backed by '.' or to an equivalent non-file based
1412
relpath provides for clients to get a path relative to the base url.
1413
These should only be downwards relative, not upwards.
1415
base = self.get_server().get_url()
1416
return self._adjust_url(base, relpath)
1418
def get_vfs_only_url(self, relpath=None):
1419
"""Get a URL (or maybe a path for the plain old vfs transport.
1421
This will never be a smart protocol.
1422
:param relpath: provides for clients to get a path relative to the base
1423
url. These should only be downwards relative, not upwards.
1425
base = self.get_vfs_only_server().get_url()
1426
return self._adjust_url(base, relpath)
1428
def _make_test_root(self):
1429
if TestCaseWithMemoryTransport.TEST_ROOT is not None:
1433
root = u'test%04d.tmp' % i
1437
if e.errno == errno.EEXIST:
1442
# successfully created
1443
TestCaseWithMemoryTransport.TEST_ROOT = osutils.abspath(root)
1445
# make a fake bzr directory there to prevent any tests propagating
1446
# up onto the source directory's real branch
1447
bzrdir.BzrDir.create_standalone_workingtree(
1448
TestCaseWithMemoryTransport.TEST_ROOT)
1450
def makeAndChdirToTestDir(self):
1451
"""Create a temporary directories for this one test.
1453
This must set self.test_home_dir and self.test_dir and chdir to
1456
For TestCaseWithMemoryTransport we chdir to the TEST_ROOT for this test.
1458
os.chdir(TestCaseWithMemoryTransport.TEST_ROOT)
1459
self.test_dir = TestCaseWithMemoryTransport.TEST_ROOT
1460
self.test_home_dir = self.test_dir + "/MemoryTransportMissingHomeDir"
1462
def make_branch(self, relpath, format=None):
1463
"""Create a branch on the transport at relpath."""
1464
repo = self.make_repository(relpath, format=format)
1465
return repo.bzrdir.create_branch()
1467
def make_bzrdir(self, relpath, format=None):
1469
# might be a relative or absolute path
1470
maybe_a_url = self.get_url(relpath)
1471
segments = maybe_a_url.rsplit('/', 1)
1472
t = get_transport(maybe_a_url)
1473
if len(segments) > 1 and segments[-1] not in ('', '.'):
1476
except errors.FileExists:
1480
if isinstance(format, basestring):
1481
format = bzrdir.format_registry.make_bzrdir(format)
1482
return format.initialize_on_transport(t)
1483
except errors.UninitializableFormat:
1484
raise TestSkipped("Format %s is not initializable." % format)
1486
def make_repository(self, relpath, shared=False, format=None):
1487
"""Create a repository on our default transport at relpath."""
1488
made_control = self.make_bzrdir(relpath, format=format)
1489
return made_control.create_repository(shared=shared)
1491
def make_branch_and_memory_tree(self, relpath, format=None):
1492
"""Create a branch on the default transport and a MemoryTree for it."""
1493
b = self.make_branch(relpath, format=format)
1494
return memorytree.MemoryTree.create_on_branch(b)
1496
def overrideEnvironmentForTesting(self):
1497
os.environ['HOME'] = self.test_home_dir
1498
os.environ['APPDATA'] = self.test_home_dir
1501
super(TestCaseWithMemoryTransport, self).setUp()
1502
self._make_test_root()
1503
_currentdir = os.getcwdu()
1504
def _leaveDirectory():
1505
os.chdir(_currentdir)
1506
self.addCleanup(_leaveDirectory)
1507
self.makeAndChdirToTestDir()
1508
self.overrideEnvironmentForTesting()
1509
self.__readonly_server = None
1510
self.__server = None
1513
class TestCaseInTempDir(TestCaseWithMemoryTransport):
1514
"""Derived class that runs a test within a temporary directory.
1516
This is useful for tests that need to create a branch, etc.
1518
The directory is created in a slightly complex way: for each
1519
Python invocation, a new temporary top-level directory is created.
1520
All test cases create their own directory within that. If the
1521
tests complete successfully, the directory is removed.
1523
InTempDir is an old alias for FunctionalTestCase.
1526
OVERRIDE_PYTHON = 'python'
1528
def check_file_contents(self, filename, expect):
1529
self.log("check contents of file %s" % filename)
1530
contents = file(filename, 'r').read()
1531
if contents != expect:
1532
self.log("expected: %r" % expect)
1533
self.log("actually: %r" % contents)
1534
self.fail("contents of %s not as expected" % filename)
1536
def makeAndChdirToTestDir(self):
1537
"""See TestCaseWithMemoryTransport.makeAndChdirToTestDir().
1539
For TestCaseInTempDir we create a temporary directory based on the test
1540
name and then create two subdirs - test and home under it.
1542
# shorten the name, to avoid test failures due to path length
1543
short_id = self.id().replace('bzrlib.tests.', '') \
1544
.replace('__main__.', '')[-100:]
1545
# it's possible the same test class is run several times for
1546
# parameterized tests, so make sure the names don't collide.
1550
candidate_dir = '%s/%s.%d' % (self.TEST_ROOT, short_id, i)
1552
candidate_dir = '%s/%s' % (self.TEST_ROOT, short_id)
1553
if os.path.exists(candidate_dir):
1557
os.mkdir(candidate_dir)
1558
self.test_home_dir = candidate_dir + '/home'
1559
os.mkdir(self.test_home_dir)
1560
self.test_dir = candidate_dir + '/work'
1561
os.mkdir(self.test_dir)
1562
os.chdir(self.test_dir)
1565
def build_tree(self, shape, line_endings='binary', transport=None):
1566
"""Build a test tree according to a pattern.
1568
shape is a sequence of file specifications. If the final
1569
character is '/', a directory is created.
1571
This assumes that all the elements in the tree being built are new.
1573
This doesn't add anything to a branch.
1574
:param line_endings: Either 'binary' or 'native'
1575
in binary mode, exact contents are written
1576
in native mode, the line endings match the
1577
default platform endings.
1579
:param transport: A transport to write to, for building trees on
1580
VFS's. If the transport is readonly or None,
1581
"." is opened automatically.
1583
# It's OK to just create them using forward slashes on windows.
1584
if transport is None or transport.is_readonly():
1585
transport = get_transport(".")
1587
self.assert_(isinstance(name, basestring))
1589
transport.mkdir(urlutils.escape(name[:-1]))
1591
if line_endings == 'binary':
1593
elif line_endings == 'native':
1596
raise errors.BzrError(
1597
'Invalid line ending request %r' % line_endings)
1598
content = "contents of %s%s" % (name.encode('utf-8'), end)
1599
transport.put_bytes_non_atomic(urlutils.escape(name), content)
1601
def build_tree_contents(self, shape):
1602
build_tree_contents(shape)
1604
def assertFileEqual(self, content, path):
1605
"""Fail if path does not contain 'content'."""
1606
self.failUnlessExists(path)
1607
# TODO: jam 20060427 Shouldn't this be 'rb'?
1608
self.assertEqualDiff(content, open(path, 'r').read())
1610
def failUnlessExists(self, path):
1611
"""Fail unless path, which may be abs or relative, exists."""
1612
self.failUnless(osutils.lexists(path),path+" does not exist")
1614
def failIfExists(self, path):
1615
"""Fail if path, which may be abs or relative, exists."""
1616
self.failIf(osutils.lexists(path),path+" exists")
1619
class TestCaseWithTransport(TestCaseInTempDir):
1620
"""A test case that provides get_url and get_readonly_url facilities.
1622
These back onto two transport servers, one for readonly access and one for
1625
If no explicit class is provided for readonly access, a
1626
ReadonlyTransportDecorator is used instead which allows the use of non disk
1627
based read write transports.
1629
If an explicit class is provided for readonly access, that server and the
1630
readwrite one must both define get_url() as resolving to os.getcwd().
1633
def get_vfs_only_server(self):
1634
"""See TestCaseWithMemoryTransport.
1636
This is useful for some tests with specific servers that need
1639
if self.__vfs_server is None:
1640
self.__vfs_server = self.vfs_transport_factory()
1641
self.__vfs_server.setUp()
1642
self.addCleanup(self.__vfs_server.tearDown)
1643
return self.__vfs_server
1645
def make_branch_and_tree(self, relpath, format=None):
1646
"""Create a branch on the transport and a tree locally.
1648
If the transport is not a LocalTransport, the Tree can't be created on
1649
the transport. In that case the working tree is created in the local
1650
directory backing the transport, and the returned tree's branch and
1651
repository will also be accessed locally.
1653
If the original default transport for this test case isn't backed by the
1654
working directory, this will return a checkout.
1656
:param format: The BzrDirFormat.
1657
:returns: the WorkingTree.
1659
# TODO: always use the local disk path for the working tree,
1660
# this obviously requires a format that supports branch references
1661
# so check for that by checking bzrdir.BzrDirFormat.get_default_format()
1663
b = self.make_branch(relpath, format=format)
1665
return b.bzrdir.create_workingtree()
1666
except errors.NotLocalUrl:
1667
# We can only make working trees locally at the moment. If the
1668
# transport can't support them, then we keep the non-disk-backed
1669
# branch and create a local checkout.
1670
if not os.path.exists('_checkouts'):
1671
os.mkdir('_checkouts')
1672
return b.create_checkout('_checkouts/' + relpath)
1674
def assertIsDirectory(self, relpath, transport):
1675
"""Assert that relpath within transport is a directory.
1677
This may not be possible on all transports; in that case it propagates
1678
a TransportNotPossible.
1681
mode = transport.stat(relpath).st_mode
1682
except errors.NoSuchFile:
1683
self.fail("path %s is not a directory; no such file"
1685
if not stat.S_ISDIR(mode):
1686
self.fail("path %s is not a directory; has mode %#o"
1690
super(TestCaseWithTransport, self).setUp()
1691
self.__vfs_server = None
1694
class ChrootedTestCase(TestCaseWithTransport):
1695
"""A support class that provides readonly urls outside the local namespace.
1697
This is done by checking if self.transport_server is a MemoryServer. if it
1698
is then we are chrooted already, if it is not then an HttpServer is used
1701
TODO RBC 20060127: make this an option to TestCaseWithTransport so it can
1702
be used without needed to redo it when a different
1703
subclass is in use ?
1707
super(ChrootedTestCase, self).setUp()
1708
# NB: one HttpServer is taught to decorate properly,
1709
# this hack can be removed.
1710
if not self.vfs_transport_factory == MemoryServer:
1711
self.transport_readonly_server = HttpServer
1714
def filter_suite_by_re(suite, pattern):
1715
result = TestUtil.TestSuite()
1716
filter_re = re.compile(pattern)
1717
for test in iter_suite_tests(suite):
1718
if filter_re.search(test.id()):
1719
result.addTest(test)
1723
def sort_suite_by_re(suite, pattern):
1726
filter_re = re.compile(pattern)
1727
for test in iter_suite_tests(suite):
1728
if filter_re.search(test.id()):
1732
return TestUtil.TestSuite(first + second)
1735
def run_suite(suite, name='test', verbose=False, pattern=".*",
1736
stop_on_failure=False, keep_output=False,
1737
transport=None, lsprof_timed=None, bench_history=None,
1738
matching_tests_first=None):
1739
TestCase._gather_lsprof_in_benchmarks = lsprof_timed
1744
runner = TextTestRunner(stream=sys.stdout,
1746
verbosity=verbosity,
1747
keep_output=keep_output,
1748
bench_history=bench_history)
1749
runner.stop_on_failure=stop_on_failure
1751
if matching_tests_first:
1752
suite = sort_suite_by_re(suite, pattern)
1754
suite = filter_suite_by_re(suite, pattern)
1755
result = runner.run(suite)
1756
return result.wasSuccessful()
1759
def selftest(verbose=False, pattern=".*", stop_on_failure=True,
1762
test_suite_factory=None,
1765
matching_tests_first=None):
1766
"""Run the whole test suite under the enhanced runner"""
1767
# XXX: Very ugly way to do this...
1768
# Disable warning about old formats because we don't want it to disturb
1769
# any blackbox tests.
1770
from bzrlib import repository
1771
repository._deprecation_warning_done = True
1773
global default_transport
1774
if transport is None:
1775
transport = default_transport
1776
old_transport = default_transport
1777
default_transport = transport
1779
if test_suite_factory is None:
1780
suite = test_suite()
1782
suite = test_suite_factory()
1783
return run_suite(suite, 'testbzr', verbose=verbose, pattern=pattern,
1784
stop_on_failure=stop_on_failure, keep_output=keep_output,
1785
transport=transport,
1786
lsprof_timed=lsprof_timed,
1787
bench_history=bench_history,
1788
matching_tests_first=matching_tests_first)
1790
default_transport = old_transport
1794
"""Build and return TestSuite for the whole of bzrlib.
1796
This function can be replaced if you need to change the default test
1797
suite on a global basis, but it is not encouraged.
1800
'bzrlib.tests.test_ancestry',
1801
'bzrlib.tests.test_annotate',
1802
'bzrlib.tests.test_api',
1803
'bzrlib.tests.test_atomicfile',
1804
'bzrlib.tests.test_bad_files',
1805
'bzrlib.tests.test_branch',
1806
'bzrlib.tests.test_bundle',
1807
'bzrlib.tests.test_bzrdir',
1808
'bzrlib.tests.test_cache_utf8',
1809
'bzrlib.tests.test_commands',
1810
'bzrlib.tests.test_commit',
1811
'bzrlib.tests.test_commit_merge',
1812
'bzrlib.tests.test_config',
1813
'bzrlib.tests.test_conflicts',
1814
'bzrlib.tests.test_decorators',
1815
'bzrlib.tests.test_delta',
1816
'bzrlib.tests.test_diff',
1817
'bzrlib.tests.test_doc_generate',
1818
'bzrlib.tests.test_errors',
1819
'bzrlib.tests.test_escaped_store',
1820
'bzrlib.tests.test_fetch',
1821
'bzrlib.tests.test_ftp_transport',
1822
'bzrlib.tests.test_generate_docs',
1823
'bzrlib.tests.test_generate_ids',
1824
'bzrlib.tests.test_globbing',
1825
'bzrlib.tests.test_gpg',
1826
'bzrlib.tests.test_graph',
1827
'bzrlib.tests.test_hashcache',
1828
'bzrlib.tests.test_http',
1829
'bzrlib.tests.test_http_response',
1830
'bzrlib.tests.test_https_ca_bundle',
1831
'bzrlib.tests.test_identitymap',
1832
'bzrlib.tests.test_ignores',
1833
'bzrlib.tests.test_inv',
1834
'bzrlib.tests.test_knit',
1835
'bzrlib.tests.test_lazy_import',
1836
'bzrlib.tests.test_lazy_regex',
1837
'bzrlib.tests.test_lockdir',
1838
'bzrlib.tests.test_lockable_files',
1839
'bzrlib.tests.test_log',
1840
'bzrlib.tests.test_memorytree',
1841
'bzrlib.tests.test_merge',
1842
'bzrlib.tests.test_merge3',
1843
'bzrlib.tests.test_merge_core',
1844
'bzrlib.tests.test_missing',
1845
'bzrlib.tests.test_msgeditor',
1846
'bzrlib.tests.test_nonascii',
1847
'bzrlib.tests.test_options',
1848
'bzrlib.tests.test_osutils',
1849
'bzrlib.tests.test_osutils_encodings',
1850
'bzrlib.tests.test_patch',
1851
'bzrlib.tests.test_patches',
1852
'bzrlib.tests.test_permissions',
1853
'bzrlib.tests.test_plugins',
1854
'bzrlib.tests.test_progress',
1855
'bzrlib.tests.test_reconcile',
1856
'bzrlib.tests.test_registry',
1857
'bzrlib.tests.test_remote',
1858
'bzrlib.tests.test_repository',
1859
'bzrlib.tests.test_revert',
1860
'bzrlib.tests.test_revision',
1861
'bzrlib.tests.test_revisionnamespaces',
1862
'bzrlib.tests.test_revisiontree',
1863
'bzrlib.tests.test_rio',
1864
'bzrlib.tests.test_sampler',
1865
'bzrlib.tests.test_selftest',
1866
'bzrlib.tests.test_setup',
1867
'bzrlib.tests.test_sftp_transport',
1868
'bzrlib.tests.test_smart',
1869
'bzrlib.tests.test_smart_add',
1870
'bzrlib.tests.test_smart_transport',
1871
'bzrlib.tests.test_source',
1872
'bzrlib.tests.test_status',
1873
'bzrlib.tests.test_store',
1874
'bzrlib.tests.test_symbol_versioning',
1875
'bzrlib.tests.test_testament',
1876
'bzrlib.tests.test_textfile',
1877
'bzrlib.tests.test_textmerge',
1878
'bzrlib.tests.test_trace',
1879
'bzrlib.tests.test_transactions',
1880
'bzrlib.tests.test_transform',
1881
'bzrlib.tests.test_transport',
1882
'bzrlib.tests.test_tree',
1883
'bzrlib.tests.test_treebuilder',
1884
'bzrlib.tests.test_tsort',
1885
'bzrlib.tests.test_tuned_gzip',
1886
'bzrlib.tests.test_ui',
1887
'bzrlib.tests.test_upgrade',
1888
'bzrlib.tests.test_urlutils',
1889
'bzrlib.tests.test_versionedfile',
1890
'bzrlib.tests.test_version',
1891
'bzrlib.tests.test_version_info',
1892
'bzrlib.tests.test_weave',
1893
'bzrlib.tests.test_whitebox',
1894
'bzrlib.tests.test_workingtree',
1895
'bzrlib.tests.test_wsgi',
1896
'bzrlib.tests.test_xml',
1898
test_transport_implementations = [
1899
'bzrlib.tests.test_transport_implementations',
1900
'bzrlib.tests.test_read_bundle',
1902
suite = TestUtil.TestSuite()
1903
loader = TestUtil.TestLoader()
1904
suite.addTest(loader.loadTestsFromModuleNames(testmod_names))
1905
from bzrlib.transport import TransportTestProviderAdapter
1906
adapter = TransportTestProviderAdapter()
1907
adapt_modules(test_transport_implementations, adapter, loader, suite)
1908
for package in packages_to_test():
1909
suite.addTest(package.test_suite())
1910
for m in MODULES_TO_TEST:
1911
suite.addTest(loader.loadTestsFromModule(m))
1912
for m in MODULES_TO_DOCTEST:
1914
suite.addTest(doctest.DocTestSuite(m))
1915
except ValueError, e:
1916
print '**failed to get doctest for: %s\n%s' %(m,e)
1918
for name, plugin in bzrlib.plugin.all_plugins().items():
1919
if getattr(plugin, 'test_suite', None) is not None:
1920
default_encoding = sys.getdefaultencoding()
1922
plugin_suite = plugin.test_suite()
1923
except ImportError, e:
1924
bzrlib.trace.warning(
1925
'Unable to test plugin "%s": %s', name, e)
1927
suite.addTest(plugin_suite)
1928
if default_encoding != sys.getdefaultencoding():
1929
bzrlib.trace.warning(
1930
'Plugin "%s" tried to reset default encoding to: %s', name,
1931
sys.getdefaultencoding())
1933
sys.setdefaultencoding(default_encoding)
1937
def adapt_modules(mods_list, adapter, loader, suite):
1938
"""Adapt the modules in mods_list using adapter and add to suite."""
1939
for test in iter_suite_tests(loader.loadTestsFromModuleNames(mods_list)):
1940
suite.addTests(adapter.adapt(test))
1943
def clean_selftest_output(root=None, quiet=False):
1944
"""Remove all selftest output directories from root directory.
1946
:param root: root directory for clean
1947
(if ommitted or None then clean current directory).
1948
:param quiet: suppress report about deleting directories
1953
re_dir = re.compile(r'''test\d\d\d\d\.tmp''')
1956
for i in os.listdir(root):
1957
if os.path.isdir(i) and re_dir.match(i):
1959
print 'delete directory:', i