1
# Copyright (C) 2005, 2006, 2007 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 "%r" not found in "%r"'
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 deprecation warning 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.
998
:param retcode: The status code the command should return
999
:param working_dir: The directory to run the command in
1001
retcode = kwargs.pop('retcode', 0)
1002
encoding = kwargs.pop('encoding', None)
1003
stdin = kwargs.pop('stdin', None)
1004
working_dir = kwargs.pop('working_dir', None)
1005
return self.run_bzr_captured(args, retcode=retcode, encoding=encoding,
1006
stdin=stdin, working_dir=working_dir)
1008
def run_bzr_decode(self, *args, **kwargs):
1009
if 'encoding' in kwargs:
1010
encoding = kwargs['encoding']
1012
encoding = bzrlib.user_encoding
1013
return self.run_bzr(*args, **kwargs)[0].decode(encoding)
1015
def run_bzr_error(self, error_regexes, *args, **kwargs):
1016
"""Run bzr, and check that stderr contains the supplied regexes
1018
:param error_regexes: Sequence of regular expressions which
1019
must each be found in the error output. The relative ordering
1021
:param args: command-line arguments for bzr
1022
:param kwargs: Keyword arguments which are interpreted by run_bzr
1023
This function changes the default value of retcode to be 3,
1024
since in most cases this is run when you expect bzr to fail.
1025
:return: (out, err) The actual output of running the command (in case you
1026
want to do more inspection)
1029
# Make sure that commit is failing because there is nothing to do
1030
self.run_bzr_error(['no changes to commit'],
1031
'commit', '-m', 'my commit comment')
1032
# Make sure --strict is handling an unknown file, rather than
1033
# giving us the 'nothing to do' error
1034
self.build_tree(['unknown'])
1035
self.run_bzr_error(['Commit refused because there are unknown files'],
1036
'commit', '--strict', '-m', 'my commit comment')
1038
kwargs.setdefault('retcode', 3)
1039
out, err = self.run_bzr(*args, **kwargs)
1040
for regex in error_regexes:
1041
self.assertContainsRe(err, regex)
1044
def run_bzr_subprocess(self, *args, **kwargs):
1045
"""Run bzr in a subprocess for testing.
1047
This starts a new Python interpreter and runs bzr in there.
1048
This should only be used for tests that have a justifiable need for
1049
this isolation: e.g. they are testing startup time, or signal
1050
handling, or early startup code, etc. Subprocess code can't be
1051
profiled or debugged so easily.
1053
:param retcode: The status code that is expected. Defaults to 0. If
1054
None is supplied, the status code is not checked.
1055
:param env_changes: A dictionary which lists changes to environment
1056
variables. A value of None will unset the env variable.
1057
The values must be strings. The change will only occur in the
1058
child, so you don't need to fix the environment after running.
1059
:param universal_newlines: Convert CRLF => LF
1060
:param allow_plugins: By default the subprocess is run with
1061
--no-plugins to ensure test reproducibility. Also, it is possible
1062
for system-wide plugins to create unexpected output on stderr,
1063
which can cause unnecessary test failures.
1065
env_changes = kwargs.get('env_changes', {})
1066
working_dir = kwargs.get('working_dir', None)
1067
allow_plugins = kwargs.get('allow_plugins', False)
1068
process = self.start_bzr_subprocess(args, env_changes=env_changes,
1069
working_dir=working_dir,
1070
allow_plugins=allow_plugins)
1071
# We distinguish between retcode=None and retcode not passed.
1072
supplied_retcode = kwargs.get('retcode', 0)
1073
return self.finish_bzr_subprocess(process, retcode=supplied_retcode,
1074
universal_newlines=kwargs.get('universal_newlines', False),
1077
def start_bzr_subprocess(self, process_args, env_changes=None,
1078
skip_if_plan_to_signal=False,
1080
allow_plugins=False):
1081
"""Start bzr in a subprocess for testing.
1083
This starts a new Python interpreter and runs bzr in there.
1084
This should only be used for tests that have a justifiable need for
1085
this isolation: e.g. they are testing startup time, or signal
1086
handling, or early startup code, etc. Subprocess code can't be
1087
profiled or debugged so easily.
1089
:param process_args: a list of arguments to pass to the bzr executable,
1090
for example `['--version']`.
1091
:param env_changes: A dictionary which lists changes to environment
1092
variables. A value of None will unset the env variable.
1093
The values must be strings. The change will only occur in the
1094
child, so you don't need to fix the environment after running.
1095
:param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
1097
:param allow_plugins: If False (default) pass --no-plugins to bzr.
1099
:returns: Popen object for the started process.
1101
if skip_if_plan_to_signal:
1102
if not getattr(os, 'kill', None):
1103
raise TestSkipped("os.kill not available.")
1105
if env_changes is None:
1109
def cleanup_environment():
1110
for env_var, value in env_changes.iteritems():
1111
old_env[env_var] = osutils.set_or_unset_env(env_var, value)
1113
def restore_environment():
1114
for env_var, value in old_env.iteritems():
1115
osutils.set_or_unset_env(env_var, value)
1117
bzr_path = self.get_bzr_path()
1120
if working_dir is not None:
1121
cwd = osutils.getcwd()
1122
os.chdir(working_dir)
1125
# win32 subprocess doesn't support preexec_fn
1126
# so we will avoid using it on all platforms, just to
1127
# make sure the code path is used, and we don't break on win32
1128
cleanup_environment()
1129
command = [sys.executable, bzr_path]
1130
if not allow_plugins:
1131
command.append('--no-plugins')
1132
command.extend(process_args)
1133
process = self._popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE)
1135
restore_environment()
1141
def _popen(self, *args, **kwargs):
1142
"""Place a call to Popen.
1144
Allows tests to override this method to intercept the calls made to
1145
Popen for introspection.
1147
return Popen(*args, **kwargs)
1149
def get_bzr_path(self):
1150
"""Return the path of the 'bzr' executable for this test suite."""
1151
bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
1152
if not os.path.isfile(bzr_path):
1153
# We are probably installed. Assume sys.argv is the right file
1154
bzr_path = sys.argv[0]
1157
def finish_bzr_subprocess(self, process, retcode=0, send_signal=None,
1158
universal_newlines=False, process_args=None):
1159
"""Finish the execution of process.
1161
:param process: the Popen object returned from start_bzr_subprocess.
1162
:param retcode: The status code that is expected. Defaults to 0. If
1163
None is supplied, the status code is not checked.
1164
:param send_signal: an optional signal to send to the process.
1165
:param universal_newlines: Convert CRLF => LF
1166
:returns: (stdout, stderr)
1168
if send_signal is not None:
1169
os.kill(process.pid, send_signal)
1170
out, err = process.communicate()
1172
if universal_newlines:
1173
out = out.replace('\r\n', '\n')
1174
err = err.replace('\r\n', '\n')
1176
if retcode is not None and retcode != process.returncode:
1177
if process_args is None:
1178
process_args = "(unknown args)"
1179
mutter('Output of bzr %s:\n%s', process_args, out)
1180
mutter('Error for bzr %s:\n%s', process_args, err)
1181
self.fail('Command bzr %s failed with retcode %s != %s'
1182
% (process_args, retcode, process.returncode))
1185
def check_inventory_shape(self, inv, shape):
1186
"""Compare an inventory to a list of expected names.
1188
Fail if they are not precisely equal.
1191
shape = list(shape) # copy
1192
for path, ie in inv.entries():
1193
name = path.replace('\\', '/')
1194
if ie.kind == 'dir':
1201
self.fail("expected paths not found in inventory: %r" % shape)
1203
self.fail("unexpected paths found in inventory: %r" % extras)
1205
def apply_redirected(self, stdin=None, stdout=None, stderr=None,
1206
a_callable=None, *args, **kwargs):
1207
"""Call callable with redirected std io pipes.
1209
Returns the return code."""
1210
if not callable(a_callable):
1211
raise ValueError("a_callable must be callable.")
1213
stdin = StringIO("")
1215
if getattr(self, "_log_file", None) is not None:
1216
stdout = self._log_file
1220
if getattr(self, "_log_file", None is not None):
1221
stderr = self._log_file
1224
real_stdin = sys.stdin
1225
real_stdout = sys.stdout
1226
real_stderr = sys.stderr
1231
return a_callable(*args, **kwargs)
1233
sys.stdout = real_stdout
1234
sys.stderr = real_stderr
1235
sys.stdin = real_stdin
1237
@symbol_versioning.deprecated_method(symbol_versioning.zero_eleven)
1238
def merge(self, branch_from, wt_to):
1239
"""A helper for tests to do a ui-less merge.
1241
This should move to the main library when someone has time to integrate
1244
# minimal ui-less merge.
1245
wt_to.branch.fetch(branch_from)
1246
base_rev = common_ancestor(branch_from.last_revision(),
1247
wt_to.branch.last_revision(),
1248
wt_to.branch.repository)
1249
merge_inner(wt_to.branch, branch_from.basis_tree(),
1250
wt_to.branch.repository.revision_tree(base_rev),
1252
wt_to.add_parent_tree_id(branch_from.last_revision())
1255
BzrTestBase = TestCase
1258
class TestCaseWithMemoryTransport(TestCase):
1259
"""Common test class for tests that do not need disk resources.
1261
Tests that need disk resources should derive from TestCaseWithTransport.
1263
TestCaseWithMemoryTransport sets the TEST_ROOT variable for all bzr tests.
1265
For TestCaseWithMemoryTransport the test_home_dir is set to the name of
1266
a directory which does not exist. This serves to help ensure test isolation
1267
is preserved. test_dir is set to the TEST_ROOT, as is cwd, because they
1268
must exist. However, TestCaseWithMemoryTransport does not offer local
1269
file defaults for the transport in tests, nor does it obey the command line
1270
override, so tests that accidentally write to the common directory should
1278
def __init__(self, methodName='runTest'):
1279
# allow test parameterisation after test construction and before test
1280
# execution. Variables that the parameteriser sets need to be
1281
# ones that are not set by setUp, or setUp will trash them.
1282
super(TestCaseWithMemoryTransport, self).__init__(methodName)
1283
self.transport_server = default_transport
1284
self.transport_readonly_server = None
1286
def get_transport(self):
1287
"""Return a writeable transport for the test scratch space"""
1288
t = get_transport(self.get_url())
1289
self.assertFalse(t.is_readonly())
1292
def get_readonly_transport(self):
1293
"""Return a readonly transport for the test scratch space
1295
This can be used to test that operations which should only need
1296
readonly access in fact do not try to write.
1298
t = get_transport(self.get_readonly_url())
1299
self.assertTrue(t.is_readonly())
1302
def create_transport_readonly_server(self):
1303
"""Create a transport server from class defined at init.
1305
This is mostly a hook for daughter classes.
1307
return self.transport_readonly_server()
1309
def get_readonly_server(self):
1310
"""Get the server instance for the readonly transport
1312
This is useful for some tests with specific servers to do diagnostics.
1314
if self.__readonly_server is None:
1315
if self.transport_readonly_server is None:
1316
# readonly decorator requested
1317
# bring up the server
1319
self.__readonly_server = ReadonlyServer()
1320
self.__readonly_server.setUp(self.__server)
1322
self.__readonly_server = self.create_transport_readonly_server()
1323
self.__readonly_server.setUp()
1324
self.addCleanup(self.__readonly_server.tearDown)
1325
return self.__readonly_server
1327
def get_readonly_url(self, relpath=None):
1328
"""Get a URL for the readonly transport.
1330
This will either be backed by '.' or a decorator to the transport
1331
used by self.get_url()
1332
relpath provides for clients to get a path relative to the base url.
1333
These should only be downwards relative, not upwards.
1335
base = self.get_readonly_server().get_url()
1336
if relpath is not None:
1337
if not base.endswith('/'):
1339
base = base + relpath
1342
def get_server(self):
1343
"""Get the read/write server instance.
1345
This is useful for some tests with specific servers that need
1348
For TestCaseWithMemoryTransport this is always a MemoryServer, and there
1349
is no means to override it.
1351
if self.__server is None:
1352
self.__server = MemoryServer()
1353
self.__server.setUp()
1354
self.addCleanup(self.__server.tearDown)
1355
return self.__server
1357
def get_url(self, relpath=None):
1358
"""Get a URL (or maybe a path) for the readwrite transport.
1360
This will either be backed by '.' or to an equivalent non-file based
1362
relpath provides for clients to get a path relative to the base url.
1363
These should only be downwards relative, not upwards.
1365
base = self.get_server().get_url()
1366
if relpath is not None and relpath != '.':
1367
if not base.endswith('/'):
1369
# XXX: Really base should be a url; we did after all call
1370
# get_url()! But sometimes it's just a path (from
1371
# LocalAbspathServer), and it'd be wrong to append urlescaped data
1372
# to a non-escaped local path.
1373
if base.startswith('./') or base.startswith('/'):
1376
base += urlutils.escape(relpath)
1379
def _make_test_root(self):
1380
if TestCaseWithMemoryTransport.TEST_ROOT is not None:
1384
root = u'test%04d.tmp' % i
1388
if e.errno == errno.EEXIST:
1393
# successfully created
1394
TestCaseWithMemoryTransport.TEST_ROOT = osutils.abspath(root)
1396
# make a fake bzr directory there to prevent any tests propagating
1397
# up onto the source directory's real branch
1398
bzrdir.BzrDir.create_standalone_workingtree(
1399
TestCaseWithMemoryTransport.TEST_ROOT)
1401
def makeAndChdirToTestDir(self):
1402
"""Create a temporary directories for this one test.
1404
This must set self.test_home_dir and self.test_dir and chdir to
1407
For TestCaseWithMemoryTransport we chdir to the TEST_ROOT for this test.
1409
os.chdir(TestCaseWithMemoryTransport.TEST_ROOT)
1410
self.test_dir = TestCaseWithMemoryTransport.TEST_ROOT
1411
self.test_home_dir = self.test_dir + "/MemoryTransportMissingHomeDir"
1413
def make_branch(self, relpath, format=None):
1414
"""Create a branch on the transport at relpath."""
1415
repo = self.make_repository(relpath, format=format)
1416
return repo.bzrdir.create_branch()
1418
def make_bzrdir(self, relpath, format=None):
1420
# might be a relative or absolute path
1421
maybe_a_url = self.get_url(relpath)
1422
segments = maybe_a_url.rsplit('/', 1)
1423
t = get_transport(maybe_a_url)
1424
if len(segments) > 1 and segments[-1] not in ('', '.'):
1427
except errors.FileExists:
1431
if isinstance(format, basestring):
1432
format = bzrdir.format_registry.make_bzrdir(format)
1433
return format.initialize_on_transport(t)
1434
except errors.UninitializableFormat:
1435
raise TestSkipped("Format %s is not initializable." % format)
1437
def make_repository(self, relpath, shared=False, format=None):
1438
"""Create a repository on our default transport at relpath."""
1439
made_control = self.make_bzrdir(relpath, format=format)
1440
return made_control.create_repository(shared=shared)
1442
def make_branch_and_memory_tree(self, relpath, format=None):
1443
"""Create a branch on the default transport and a MemoryTree for it."""
1444
b = self.make_branch(relpath, format=format)
1445
return memorytree.MemoryTree.create_on_branch(b)
1447
def overrideEnvironmentForTesting(self):
1448
os.environ['HOME'] = self.test_home_dir
1449
os.environ['APPDATA'] = self.test_home_dir
1452
super(TestCaseWithMemoryTransport, self).setUp()
1453
self._make_test_root()
1454
_currentdir = os.getcwdu()
1455
def _leaveDirectory():
1456
os.chdir(_currentdir)
1457
self.addCleanup(_leaveDirectory)
1458
self.makeAndChdirToTestDir()
1459
self.overrideEnvironmentForTesting()
1460
self.__readonly_server = None
1461
self.__server = None
1464
class TestCaseInTempDir(TestCaseWithMemoryTransport):
1465
"""Derived class that runs a test within a temporary directory.
1467
This is useful for tests that need to create a branch, etc.
1469
The directory is created in a slightly complex way: for each
1470
Python invocation, a new temporary top-level directory is created.
1471
All test cases create their own directory within that. If the
1472
tests complete successfully, the directory is removed.
1474
InTempDir is an old alias for FunctionalTestCase.
1477
OVERRIDE_PYTHON = 'python'
1479
def check_file_contents(self, filename, expect):
1480
self.log("check contents of file %s" % filename)
1481
contents = file(filename, 'r').read()
1482
if contents != expect:
1483
self.log("expected: %r" % expect)
1484
self.log("actually: %r" % contents)
1485
self.fail("contents of %s not as expected" % filename)
1487
def makeAndChdirToTestDir(self):
1488
"""See TestCaseWithMemoryTransport.makeAndChdirToTestDir().
1490
For TestCaseInTempDir we create a temporary directory based on the test
1491
name and then create two subdirs - test and home under it.
1493
# shorten the name, to avoid test failures due to path length
1494
short_id = self.id().replace('bzrlib.tests.', '') \
1495
.replace('__main__.', '')[-100:]
1496
# it's possible the same test class is run several times for
1497
# parameterized tests, so make sure the names don't collide.
1501
candidate_dir = '%s/%s.%d' % (self.TEST_ROOT, short_id, i)
1503
candidate_dir = '%s/%s' % (self.TEST_ROOT, short_id)
1504
if os.path.exists(candidate_dir):
1508
os.mkdir(candidate_dir)
1509
self.test_home_dir = candidate_dir + '/home'
1510
os.mkdir(self.test_home_dir)
1511
self.test_dir = candidate_dir + '/work'
1512
os.mkdir(self.test_dir)
1513
os.chdir(self.test_dir)
1516
def build_tree(self, shape, line_endings='binary', transport=None):
1517
"""Build a test tree according to a pattern.
1519
shape is a sequence of file specifications. If the final
1520
character is '/', a directory is created.
1522
This assumes that all the elements in the tree being built are new.
1524
This doesn't add anything to a branch.
1525
:param line_endings: Either 'binary' or 'native'
1526
in binary mode, exact contents are written
1527
in native mode, the line endings match the
1528
default platform endings.
1530
:param transport: A transport to write to, for building trees on
1531
VFS's. If the transport is readonly or None,
1532
"." is opened automatically.
1534
# It's OK to just create them using forward slashes on windows.
1535
if transport is None or transport.is_readonly():
1536
transport = get_transport(".")
1538
self.assert_(isinstance(name, basestring))
1540
transport.mkdir(urlutils.escape(name[:-1]))
1542
if line_endings == 'binary':
1544
elif line_endings == 'native':
1547
raise errors.BzrError(
1548
'Invalid line ending request %r' % line_endings)
1549
content = "contents of %s%s" % (name.encode('utf-8'), end)
1550
transport.put_bytes_non_atomic(urlutils.escape(name), content)
1552
def build_tree_contents(self, shape):
1553
build_tree_contents(shape)
1555
def assertFileEqual(self, content, path):
1556
"""Fail if path does not contain 'content'."""
1557
self.failUnlessExists(path)
1558
# TODO: jam 20060427 Shouldn't this be 'rb'?
1559
self.assertEqualDiff(content, open(path, 'r').read())
1561
def failUnlessExists(self, path):
1562
"""Fail unless path, which may be abs or relative, exists."""
1563
self.failUnless(osutils.lexists(path),path+" does not exist")
1565
def failIfExists(self, path):
1566
"""Fail if path, which may be abs or relative, exists."""
1567
self.failIf(osutils.lexists(path),path+" exists")
1570
class TestCaseWithTransport(TestCaseInTempDir):
1571
"""A test case that provides get_url and get_readonly_url facilities.
1573
These back onto two transport servers, one for readonly access and one for
1576
If no explicit class is provided for readonly access, a
1577
ReadonlyTransportDecorator is used instead which allows the use of non disk
1578
based read write transports.
1580
If an explicit class is provided for readonly access, that server and the
1581
readwrite one must both define get_url() as resolving to os.getcwd().
1584
def create_transport_server(self):
1585
"""Create a transport server from class defined at init.
1587
This is mostly a hook for daughter classes.
1589
return self.transport_server()
1591
def get_server(self):
1592
"""See TestCaseWithMemoryTransport.
1594
This is useful for some tests with specific servers that need
1597
if self.__server is None:
1598
self.__server = self.create_transport_server()
1599
self.__server.setUp()
1600
self.addCleanup(self.__server.tearDown)
1601
return self.__server
1603
def make_branch_and_tree(self, relpath, format=None):
1604
"""Create a branch on the transport and a tree locally.
1606
If the transport is not a LocalTransport, the Tree can't be created on
1607
the transport. In that case the working tree is created in the local
1608
directory, and the returned tree's branch and repository will also be
1611
This will fail if the original default transport for this test
1612
case wasn't backed by the working directory, as the branch won't
1613
be on disk for us to open it.
1615
:param format: The BzrDirFormat.
1616
:returns: the WorkingTree.
1618
# TODO: always use the local disk path for the working tree,
1619
# this obviously requires a format that supports branch references
1620
# so check for that by checking bzrdir.BzrDirFormat.get_default_format()
1622
b = self.make_branch(relpath, format=format)
1624
return b.bzrdir.create_workingtree()
1625
except errors.NotLocalUrl:
1626
# We can only make working trees locally at the moment. If the
1627
# transport can't support them, then reopen the branch on a local
1628
# transport, and create the working tree there.
1630
# Possibly we should instead keep
1631
# the non-disk-backed branch and create a local checkout?
1632
bd = bzrdir.BzrDir.open(relpath)
1633
return bd.create_workingtree()
1635
def assertIsDirectory(self, relpath, transport):
1636
"""Assert that relpath within transport is a directory.
1638
This may not be possible on all transports; in that case it propagates
1639
a TransportNotPossible.
1642
mode = transport.stat(relpath).st_mode
1643
except errors.NoSuchFile:
1644
self.fail("path %s is not a directory; no such file"
1646
if not stat.S_ISDIR(mode):
1647
self.fail("path %s is not a directory; has mode %#o"
1650
def assertTreesEqual(self, left, right):
1651
"""Check that left and right have the same content and properties."""
1652
# we use a tree delta to check for equality of the content, and we
1653
# manually check for equality of other things such as the parents list.
1654
self.assertEqual(left.get_parent_ids(), right.get_parent_ids())
1655
differences = left.changes_from(right)
1656
self.assertFalse(differences.has_changed(),
1657
"Trees %r and %r are different: %r" % (left, right, differences))
1660
super(TestCaseWithTransport, self).setUp()
1661
self.__server = None
1664
class ChrootedTestCase(TestCaseWithTransport):
1665
"""A support class that provides readonly urls outside the local namespace.
1667
This is done by checking if self.transport_server is a MemoryServer. if it
1668
is then we are chrooted already, if it is not then an HttpServer is used
1671
TODO RBC 20060127: make this an option to TestCaseWithTransport so it can
1672
be used without needed to redo it when a different
1673
subclass is in use ?
1677
super(ChrootedTestCase, self).setUp()
1678
if not self.transport_server == MemoryServer:
1679
self.transport_readonly_server = HttpServer
1682
def filter_suite_by_re(suite, pattern):
1683
result = TestUtil.TestSuite()
1684
filter_re = re.compile(pattern)
1685
for test in iter_suite_tests(suite):
1686
if filter_re.search(test.id()):
1687
result.addTest(test)
1691
def sort_suite_by_re(suite, pattern):
1694
filter_re = re.compile(pattern)
1695
for test in iter_suite_tests(suite):
1696
if filter_re.search(test.id()):
1700
return TestUtil.TestSuite(first + second)
1703
def run_suite(suite, name='test', verbose=False, pattern=".*",
1704
stop_on_failure=False, keep_output=False,
1705
transport=None, lsprof_timed=None, bench_history=None,
1706
matching_tests_first=None):
1707
TestCase._gather_lsprof_in_benchmarks = lsprof_timed
1712
runner = TextTestRunner(stream=sys.stdout,
1714
verbosity=verbosity,
1715
keep_output=keep_output,
1716
bench_history=bench_history)
1717
runner.stop_on_failure=stop_on_failure
1719
if matching_tests_first:
1720
suite = sort_suite_by_re(suite, pattern)
1722
suite = filter_suite_by_re(suite, pattern)
1723
result = runner.run(suite)
1724
return result.wasSuccessful()
1727
def selftest(verbose=False, pattern=".*", stop_on_failure=True,
1730
test_suite_factory=None,
1733
matching_tests_first=None):
1734
"""Run the whole test suite under the enhanced runner"""
1735
# XXX: Very ugly way to do this...
1736
# Disable warning about old formats because we don't want it to disturb
1737
# any blackbox tests.
1738
from bzrlib import repository
1739
repository._deprecation_warning_done = True
1741
global default_transport
1742
if transport is None:
1743
transport = default_transport
1744
old_transport = default_transport
1745
default_transport = transport
1747
if test_suite_factory is None:
1748
suite = test_suite()
1750
suite = test_suite_factory()
1751
return run_suite(suite, 'testbzr', verbose=verbose, pattern=pattern,
1752
stop_on_failure=stop_on_failure, keep_output=keep_output,
1753
transport=transport,
1754
lsprof_timed=lsprof_timed,
1755
bench_history=bench_history,
1756
matching_tests_first=matching_tests_first)
1758
default_transport = old_transport
1762
"""Build and return TestSuite for the whole of bzrlib.
1764
This function can be replaced if you need to change the default test
1765
suite on a global basis, but it is not encouraged.
1768
'bzrlib.tests.test_ancestry',
1769
'bzrlib.tests.test_annotate',
1770
'bzrlib.tests.test_api',
1771
'bzrlib.tests.test_atomicfile',
1772
'bzrlib.tests.test_bad_files',
1773
'bzrlib.tests.test_branch',
1774
'bzrlib.tests.test_bundle',
1775
'bzrlib.tests.test_bzrdir',
1776
'bzrlib.tests.test_cache_utf8',
1777
'bzrlib.tests.test_commands',
1778
'bzrlib.tests.test_commit',
1779
'bzrlib.tests.test_commit_merge',
1780
'bzrlib.tests.test_config',
1781
'bzrlib.tests.test_conflicts',
1782
'bzrlib.tests.test_decorators',
1783
'bzrlib.tests.test_delta',
1784
'bzrlib.tests.test_diff',
1785
'bzrlib.tests.test_dirstate',
1786
'bzrlib.tests.test_doc_generate',
1787
'bzrlib.tests.test_errors',
1788
'bzrlib.tests.test_escaped_store',
1789
'bzrlib.tests.test_extract',
1790
'bzrlib.tests.test_fetch',
1791
'bzrlib.tests.test_ftp_transport',
1792
'bzrlib.tests.test_generate_docs',
1793
'bzrlib.tests.test_generate_ids',
1794
'bzrlib.tests.test_globbing',
1795
'bzrlib.tests.test_gpg',
1796
'bzrlib.tests.test_graph',
1797
'bzrlib.tests.test_hashcache',
1798
'bzrlib.tests.test_http',
1799
'bzrlib.tests.test_http_response',
1800
'bzrlib.tests.test_https_ca_bundle',
1801
'bzrlib.tests.test_identitymap',
1802
'bzrlib.tests.test_ignores',
1803
'bzrlib.tests.test_inv',
1804
'bzrlib.tests.test_knit',
1805
'bzrlib.tests.test_lazy_import',
1806
'bzrlib.tests.test_lazy_regex',
1807
'bzrlib.tests.test_lockdir',
1808
'bzrlib.tests.test_lockable_files',
1809
'bzrlib.tests.test_log',
1810
'bzrlib.tests.test_memorytree',
1811
'bzrlib.tests.test_merge',
1812
'bzrlib.tests.test_merge3',
1813
'bzrlib.tests.test_merge_core',
1814
'bzrlib.tests.test_missing',
1815
'bzrlib.tests.test_msgeditor',
1816
'bzrlib.tests.test_nonascii',
1817
'bzrlib.tests.test_options',
1818
'bzrlib.tests.test_osutils',
1819
'bzrlib.tests.test_osutils_encodings',
1820
'bzrlib.tests.test_patch',
1821
'bzrlib.tests.test_patches',
1822
'bzrlib.tests.test_permissions',
1823
'bzrlib.tests.test_plugins',
1824
'bzrlib.tests.test_progress',
1825
'bzrlib.tests.test_reconcile',
1826
'bzrlib.tests.test_registry',
1827
'bzrlib.tests.test_repository',
1828
'bzrlib.tests.test_revert',
1829
'bzrlib.tests.test_revision',
1830
'bzrlib.tests.test_revisionnamespaces',
1831
'bzrlib.tests.test_revisiontree',
1832
'bzrlib.tests.test_rio',
1833
'bzrlib.tests.test_sampler',
1834
'bzrlib.tests.test_selftest',
1835
'bzrlib.tests.test_setup',
1836
'bzrlib.tests.test_sftp_transport',
1837
'bzrlib.tests.test_smart_add',
1838
'bzrlib.tests.test_smart_transport',
1839
'bzrlib.tests.test_source',
1840
'bzrlib.tests.test_status',
1841
'bzrlib.tests.test_store',
1842
'bzrlib.tests.test_subsume',
1843
'bzrlib.tests.test_symbol_versioning',
1844
'bzrlib.tests.test_tag',
1845
'bzrlib.tests.test_testament',
1846
'bzrlib.tests.test_textfile',
1847
'bzrlib.tests.test_textmerge',
1848
'bzrlib.tests.test_trace',
1849
'bzrlib.tests.test_transactions',
1850
'bzrlib.tests.test_transform',
1851
'bzrlib.tests.test_transport',
1852
'bzrlib.tests.test_tree',
1853
'bzrlib.tests.test_treebuilder',
1854
'bzrlib.tests.test_tsort',
1855
'bzrlib.tests.test_tuned_gzip',
1856
'bzrlib.tests.test_ui',
1857
'bzrlib.tests.test_upgrade',
1858
'bzrlib.tests.test_urlutils',
1859
'bzrlib.tests.test_versionedfile',
1860
'bzrlib.tests.test_version',
1861
'bzrlib.tests.test_version_info',
1862
'bzrlib.tests.test_weave',
1863
'bzrlib.tests.test_whitebox',
1864
'bzrlib.tests.test_workingtree',
1865
'bzrlib.tests.test_workingtree_4',
1866
'bzrlib.tests.test_wsgi',
1867
'bzrlib.tests.test_xml',
1869
test_transport_implementations = [
1870
'bzrlib.tests.test_transport_implementations',
1871
'bzrlib.tests.test_read_bundle',
1873
suite = TestUtil.TestSuite()
1874
loader = TestUtil.TestLoader()
1875
suite.addTest(loader.loadTestsFromModuleNames(testmod_names))
1876
from bzrlib.transport import TransportTestProviderAdapter
1877
adapter = TransportTestProviderAdapter()
1878
adapt_modules(test_transport_implementations, adapter, loader, suite)
1879
for package in packages_to_test():
1880
suite.addTest(package.test_suite())
1881
for m in MODULES_TO_TEST:
1882
suite.addTest(loader.loadTestsFromModule(m))
1883
for m in MODULES_TO_DOCTEST:
1885
suite.addTest(doctest.DocTestSuite(m))
1886
except ValueError, e:
1887
print '**failed to get doctest for: %s\n%s' %(m,e)
1889
for name, plugin in bzrlib.plugin.all_plugins().items():
1890
if getattr(plugin, 'test_suite', None) is not None:
1891
default_encoding = sys.getdefaultencoding()
1893
plugin_suite = plugin.test_suite()
1894
except ImportError, e:
1895
bzrlib.trace.warning(
1896
'Unable to test plugin "%s": %s', name, e)
1898
suite.addTest(plugin_suite)
1899
if default_encoding != sys.getdefaultencoding():
1900
bzrlib.trace.warning(
1901
'Plugin "%s" tried to reset default encoding to: %s', name,
1902
sys.getdefaultencoding())
1904
sys.setdefaultencoding(default_encoding)
1908
def adapt_modules(mods_list, adapter, loader, suite):
1909
"""Adapt the modules in mods_list using adapter and add to suite."""
1910
for test in iter_suite_tests(loader.loadTestsFromModuleNames(mods_list)):
1911
suite.addTests(adapter.adapt(test))
1914
def clean_selftest_output(root=None, quiet=False):
1915
"""Remove all selftest output directories from root directory.
1917
:param root: root directory for clean
1918
(if ommitted or None then clean current directory).
1919
:param quiet: suppress report about deleting directories
1924
re_dir = re.compile(r'''test\d\d\d\d\.tmp''')
1927
for i in os.listdir(root):
1928
if os.path.isdir(i) and re_dir.match(i):
1930
print 'delete directory:', i