102
127
bzrlib.tests.bzrdir_implementations,
103
128
bzrlib.tests.interrepository_implementations,
104
129
bzrlib.tests.interversionedfile_implementations,
130
bzrlib.tests.intertree_implementations,
105
131
bzrlib.tests.repository_implementations,
106
132
bzrlib.tests.revisionstore_implementations,
133
bzrlib.tests.tree_implementations,
107
134
bzrlib.tests.workingtree_implementations,
111
class _MyResult(unittest._TextTestResult):
112
"""Custom TestResult.
138
class ExtendedTestResult(unittest._TextTestResult):
139
"""Accepts, reports and accumulates the results of running tests.
114
Shows output in a different format, including displaying runtime for 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.
116
146
stop_early = False
118
def _elapsedTime(self):
119
return "%5dms" % (1000 * (time.time() - self._start_time))
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)
121
208
def startTest(self, test):
122
209
unittest.TestResult.startTest(self, test)
123
# In a short description, the important words are in
124
# the beginning, but in an id, the important words are
126
SHOW_DESCRIPTIONS = False
128
width = osutils.terminal_width()
129
name_width = width - 15
131
if SHOW_DESCRIPTIONS:
132
what = test.shortDescription()
134
if len(what) > name_width:
135
what = what[:name_width-3] + '...'
138
if what.startswith('bzrlib.tests.'):
140
if len(what) > name_width:
141
what = '...' + what[3-name_width:]
142
what = what.ljust(name_width)
143
self.stream.write(what)
210
self.report_test_start(test)
211
self._recordTestStartTime()
213
def _recordTestStartTime(self):
214
"""Record that a test has started."""
145
215
self._start_time = time.time()
147
217
def addError(self, test, err):
148
218
if isinstance(err[1], TestSkipped):
149
219
return self.addSkipped(test, err)
150
220
unittest.TestResult.addError(self, test, err)
152
self.stream.writeln("ERROR %s" % self._elapsedTime())
154
self.stream.write('E')
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)
156
228
if self.stop_early:
159
231
def addFailure(self, test, err):
160
232
unittest.TestResult.addFailure(self, test, err)
162
self.stream.writeln(" FAIL %s" % self._elapsedTime())
164
self.stream.write('F')
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)
166
240
if self.stop_early:
169
243
def addSuccess(self, test):
171
self.stream.writeln(' OK %s' % self._elapsedTime())
173
self.stream.write('~')
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)
175
251
unittest.TestResult.addSuccess(self, test)
177
253
def addSkipped(self, test, skip_excinfo):
179
print >>self.stream, ' SKIP %s' % self._elapsedTime()
180
print >>self.stream, ' %s' % skip_excinfo[1]
182
self.stream.write('S')
254
self.extractBenchmarkTime(test)
255
self.report_skip(test, skip_excinfo)
184
256
# seems best to treat this as success from point-of-view of unittest
185
257
# -- it actually does nothing so it barely matters :)
186
unittest.TestResult.addSuccess(self, test)
260
except KeyboardInterrupt:
263
self.addError(test, test.__exc_info())
265
unittest.TestResult.addSuccess(self, test)
188
267
def printErrorList(self, flavour, errors):
189
268
for test, err in errors:
199
278
self.stream.writeln(self.separator2)
200
279
self.stream.writeln("%s" % err)
203
class TextTestRunner(unittest.TextTestRunner):
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):
204
410
stop_on_failure = False
206
def _makeResult(self):
207
result = _MyResult(self.stream, self.descriptions, self.verbosity)
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(),
208
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
341
680
def assertIsInstance(self, obj, kls):
342
681
"""Fail if obj is not an instance of kls"""
343
682
if not isinstance(obj, kls):
344
self.fail("%r is not an instance of %s" % (obj, kls))
683
self.fail("%r is an instance of %s rather than %s" % (
684
obj, obj.__class__, kls))
686
def _capture_warnings(self, a_callable, *args, **kwargs):
687
"""A helper for callDeprecated and applyDeprecated.
689
:param a_callable: A callable to call.
690
:param args: The positional arguments for the callable
691
:param kwargs: The keyword arguments for the callable
692
:return: A tuple (warnings, result). result is the result of calling
693
a_callable(*args, **kwargs).
696
def capture_warnings(msg, cls=None, stacklevel=None):
697
# we've hooked into a deprecation specific callpath,
698
# only deprecations should getting sent via it.
699
self.assertEqual(cls, DeprecationWarning)
700
local_warnings.append(msg)
701
original_warning_method = symbol_versioning.warn
702
symbol_versioning.set_warning_method(capture_warnings)
704
result = a_callable(*args, **kwargs)
706
symbol_versioning.set_warning_method(original_warning_method)
707
return (local_warnings, result)
709
def applyDeprecated(self, deprecation_format, a_callable, *args, **kwargs):
710
"""Call a deprecated callable without warning the user.
712
:param deprecation_format: The deprecation format that the callable
713
should have been deprecated with. This is the same type as the
714
parameter to deprecated_method/deprecated_function. If the
715
callable is not deprecated with this format, an assertion error
717
:param a_callable: A callable to call. This may be a bound method or
718
a regular function. It will be called with *args and **kwargs.
719
:param args: The positional arguments for the callable
720
:param kwargs: The keyword arguments for the callable
721
:return: The result of a_callable(*args, **kwargs)
723
call_warnings, result = self._capture_warnings(a_callable,
725
expected_first_warning = symbol_versioning.deprecation_string(
726
a_callable, deprecation_format)
727
if len(call_warnings) == 0:
728
self.fail("No assertion generated by call to %s" %
730
self.assertEqual(expected_first_warning, call_warnings[0])
733
def callDeprecated(self, expected, callable, *args, **kwargs):
734
"""Assert that a callable is deprecated in a particular way.
736
This is a very precise test for unusual requirements. The
737
applyDeprecated helper function is probably more suited for most tests
738
as it allows you to simply specify the deprecation format being used
739
and will ensure that that is issued for the function being called.
741
:param expected: a list of the deprecation warnings expected, in order
742
:param callable: The callable to call
743
:param args: The positional arguments for the callable
744
:param kwargs: The keyword arguments for the callable
746
call_warnings, result = self._capture_warnings(callable,
748
self.assertEqual(expected, call_warnings)
346
751
def _startLogFile(self):
347
752
"""Send bzr and test log messages to a temporary file.
381
791
def _cleanEnvironment(self):
793
'BZR_HOME': None, # Don't inherit BZR_HOME to all the tests.
383
794
'HOME': os.getcwd(),
384
795
'APPDATA': os.getcwd(),
797
'BZREMAIL': None, # may still be present in the environment
799
'BZR_PROGRESS_BAR': None,
809
# Nobody cares about these ones AFAIK. So far at
810
# least. If you do (care), please update this comment
388
815
self.__old_env = {}
389
816
self.addCleanup(self._restoreEnvironment)
390
817
for name, value in new_env.iteritems():
391
818
self._captureVar(name, value)
394
820
def _captureVar(self, name, newvalue):
395
"""Set an environment variable, preparing it to be reset when finished."""
396
self.__old_env[name] = os.environ.get(name, None)
398
if name in os.environ:
401
os.environ[name] = newvalue
404
def _restoreVar(name, value):
406
if name in os.environ:
409
os.environ[name] = value
821
"""Set an environment variable, and reset it when finished."""
822
self.__old_env[name] = osutils.set_or_unset_env(name, newvalue)
411
824
def _restoreEnvironment(self):
412
825
for name, value in self.__old_env.iteritems():
413
self._restoreVar(name, value)
826
osutils.set_or_unset_env(name, value)
415
828
def tearDown(self):
416
829
self._runCleanups()
417
830
unittest.TestCase.tearDown(self)
832
def time(self, callable, *args, **kwargs):
833
"""Run callable and accrue the time it takes to the benchmark time.
835
If lsprofiling is enabled (i.e. by --lsprof-time to bzr selftest) then
836
this will cause lsprofile statistics to be gathered and stored in
839
if self._benchtime is None:
843
if not self._gather_lsprof_in_benchmarks:
844
return callable(*args, **kwargs)
846
# record this benchmark
847
ret, stats = bzrlib.lsprof.profile(callable, *args, **kwargs)
849
self._benchcalls.append(((callable, args, kwargs), stats))
852
self._benchtime += time.time() - start
419
854
def _runCleanups(self):
420
855
"""Run registered cleanup functions.
458
908
errors, and with logging set to something approximating the
459
909
default, so that error reporting can be checked.
461
argv -- arguments to invoke bzr
462
retcode -- expected return code, or None for don't-care.
911
:param argv: arguments to invoke bzr
912
:param retcode: expected return code, or None for don't-care.
913
:param encoding: encoding for sys.stdout and sys.stderr
914
:param stdin: A string to be used as stdin for the command.
915
:param working_dir: Change to this directory before running
466
self.log('run bzr: %s', ' '.join(argv))
918
encoding = bzrlib.user_encoding
919
if stdin is not None:
920
stdin = StringIO(stdin)
921
stdout = StringIOWrapper()
922
stderr = StringIOWrapper()
923
stdout.encoding = encoding
924
stderr.encoding = encoding
926
self.log('run bzr: %r', argv)
467
927
# FIXME: don't call into logging here
468
928
handler = logging.StreamHandler(stderr)
469
handler.setFormatter(bzrlib.trace.QuietFormatter())
470
929
handler.setLevel(logging.INFO)
471
930
logger = logging.getLogger('')
472
931
logger.addHandler(handler)
932
old_ui_factory = bzrlib.ui.ui_factory
933
bzrlib.ui.ui_factory = bzrlib.tests.blackbox.TestUIFactory(
936
bzrlib.ui.ui_factory.stdin = stdin
939
if working_dir is not None:
940
cwd = osutils.getcwd()
941
os.chdir(working_dir)
474
result = self.apply_redirected(None, stdout, stderr,
475
bzrlib.commands.run_bzr_catch_errors,
944
saved_debug_flags = frozenset(debug.debug_flags)
945
debug.debug_flags.clear()
947
result = self.apply_redirected(stdin, stdout, stderr,
948
bzrlib.commands.run_bzr_catch_errors,
951
debug.debug_flags.update(saved_debug_flags)
478
953
logger.removeHandler(handler)
954
bzrlib.ui.ui_factory = old_ui_factory
479
958
out = stdout.getvalue()
480
959
err = stderr.getvalue()
482
self.log('output:\n%s', out)
961
self.log('output:\n%r', out)
484
self.log('errors:\n%s', err)
963
self.log('errors:\n%r', err)
485
964
if retcode is not None:
486
self.assertEquals(result, retcode)
965
self.assertEquals(retcode, result)
489
968
def run_bzr(self, *args, **kwargs):
496
975
This sends the stdout/stderr results into the test's log,
497
976
where it may be useful for debugging. See also run_captured.
978
:param stdin: A string to be used as stdin for the command.
499
980
retcode = kwargs.pop('retcode', 0)
500
return self.run_bzr_captured(args, retcode)
981
encoding = kwargs.pop('encoding', None)
982
stdin = kwargs.pop('stdin', None)
983
working_dir = kwargs.pop('working_dir', None)
984
return self.run_bzr_captured(args, retcode=retcode, encoding=encoding,
985
stdin=stdin, working_dir=working_dir)
987
def run_bzr_decode(self, *args, **kwargs):
988
if 'encoding' in kwargs:
989
encoding = kwargs['encoding']
991
encoding = bzrlib.user_encoding
992
return self.run_bzr(*args, **kwargs)[0].decode(encoding)
994
def run_bzr_error(self, error_regexes, *args, **kwargs):
995
"""Run bzr, and check that stderr contains the supplied regexes
997
:param error_regexes: Sequence of regular expressions which
998
must each be found in the error output. The relative ordering
1000
:param args: command-line arguments for bzr
1001
:param kwargs: Keyword arguments which are interpreted by run_bzr
1002
This function changes the default value of retcode to be 3,
1003
since in most cases this is run when you expect bzr to fail.
1004
:return: (out, err) The actual output of running the command (in case you
1005
want to do more inspection)
1008
# Make sure that commit is failing because there is nothing to do
1009
self.run_bzr_error(['no changes to commit'],
1010
'commit', '-m', 'my commit comment')
1011
# Make sure --strict is handling an unknown file, rather than
1012
# giving us the 'nothing to do' error
1013
self.build_tree(['unknown'])
1014
self.run_bzr_error(['Commit refused because there are unknown files'],
1015
'commit', '--strict', '-m', 'my commit comment')
1017
kwargs.setdefault('retcode', 3)
1018
out, err = self.run_bzr(*args, **kwargs)
1019
for regex in error_regexes:
1020
self.assertContainsRe(err, regex)
1023
def run_bzr_subprocess(self, *args, **kwargs):
1024
"""Run bzr in a subprocess for testing.
1026
This starts a new Python interpreter and runs bzr in there.
1027
This should only be used for tests that have a justifiable need for
1028
this isolation: e.g. they are testing startup time, or signal
1029
handling, or early startup code, etc. Subprocess code can't be
1030
profiled or debugged so easily.
1032
:param retcode: The status code that is expected. Defaults to 0. If
1033
None is supplied, the status code is not checked.
1034
:param env_changes: A dictionary which lists changes to environment
1035
variables. A value of None will unset the env variable.
1036
The values must be strings. The change will only occur in the
1037
child, so you don't need to fix the environment after running.
1038
:param universal_newlines: Convert CRLF => LF
1039
:param allow_plugins: By default the subprocess is run with
1040
--no-plugins to ensure test reproducibility. Also, it is possible
1041
for system-wide plugins to create unexpected output on stderr,
1042
which can cause unnecessary test failures.
1044
env_changes = kwargs.get('env_changes', {})
1045
working_dir = kwargs.get('working_dir', None)
1046
allow_plugins = kwargs.get('allow_plugins', False)
1047
process = self.start_bzr_subprocess(args, env_changes=env_changes,
1048
working_dir=working_dir,
1049
allow_plugins=allow_plugins)
1050
# We distinguish between retcode=None and retcode not passed.
1051
supplied_retcode = kwargs.get('retcode', 0)
1052
return self.finish_bzr_subprocess(process, retcode=supplied_retcode,
1053
universal_newlines=kwargs.get('universal_newlines', False),
1056
def start_bzr_subprocess(self, process_args, env_changes=None,
1057
skip_if_plan_to_signal=False,
1059
allow_plugins=False):
1060
"""Start bzr in a subprocess for testing.
1062
This starts a new Python interpreter and runs bzr in there.
1063
This should only be used for tests that have a justifiable need for
1064
this isolation: e.g. they are testing startup time, or signal
1065
handling, or early startup code, etc. Subprocess code can't be
1066
profiled or debugged so easily.
1068
:param process_args: a list of arguments to pass to the bzr executable,
1069
for example `['--version']`.
1070
:param env_changes: A dictionary which lists changes to environment
1071
variables. A value of None will unset the env variable.
1072
The values must be strings. The change will only occur in the
1073
child, so you don't need to fix the environment after running.
1074
:param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
1076
:param allow_plugins: If False (default) pass --no-plugins to bzr.
1078
:returns: Popen object for the started process.
1080
if skip_if_plan_to_signal:
1081
if not getattr(os, 'kill', None):
1082
raise TestSkipped("os.kill not available.")
1084
if env_changes is None:
1088
def cleanup_environment():
1089
for env_var, value in env_changes.iteritems():
1090
old_env[env_var] = osutils.set_or_unset_env(env_var, value)
1092
def restore_environment():
1093
for env_var, value in old_env.iteritems():
1094
osutils.set_or_unset_env(env_var, value)
1096
bzr_path = self.get_bzr_path()
1099
if working_dir is not None:
1100
cwd = osutils.getcwd()
1101
os.chdir(working_dir)
1104
# win32 subprocess doesn't support preexec_fn
1105
# so we will avoid using it on all platforms, just to
1106
# make sure the code path is used, and we don't break on win32
1107
cleanup_environment()
1108
command = [sys.executable, bzr_path]
1109
if not allow_plugins:
1110
command.append('--no-plugins')
1111
command.extend(process_args)
1112
process = self._popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE)
1114
restore_environment()
1120
def _popen(self, *args, **kwargs):
1121
"""Place a call to Popen.
1123
Allows tests to override this method to intercept the calls made to
1124
Popen for introspection.
1126
return Popen(*args, **kwargs)
1128
def get_bzr_path(self):
1129
"""Return the path of the 'bzr' executable for this test suite."""
1130
bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
1131
if not os.path.isfile(bzr_path):
1132
# We are probably installed. Assume sys.argv is the right file
1133
bzr_path = sys.argv[0]
1136
def finish_bzr_subprocess(self, process, retcode=0, send_signal=None,
1137
universal_newlines=False, process_args=None):
1138
"""Finish the execution of process.
1140
:param process: the Popen object returned from start_bzr_subprocess.
1141
:param retcode: The status code that is expected. Defaults to 0. If
1142
None is supplied, the status code is not checked.
1143
:param send_signal: an optional signal to send to the process.
1144
:param universal_newlines: Convert CRLF => LF
1145
:returns: (stdout, stderr)
1147
if send_signal is not None:
1148
os.kill(process.pid, send_signal)
1149
out, err = process.communicate()
1151
if universal_newlines:
1152
out = out.replace('\r\n', '\n')
1153
err = err.replace('\r\n', '\n')
1155
if retcode is not None and retcode != process.returncode:
1156
if process_args is None:
1157
process_args = "(unknown args)"
1158
mutter('Output of bzr %s:\n%s', process_args, out)
1159
mutter('Error for bzr %s:\n%s', process_args, err)
1160
self.fail('Command bzr %s failed with retcode %s != %s'
1161
% (process_args, retcode, process.returncode))
502
1164
def check_inventory_shape(self, inv, shape):
503
1165
"""Compare an inventory to a list of expected names.
562
1225
base_rev = common_ancestor(branch_from.last_revision(),
563
1226
wt_to.branch.last_revision(),
564
1227
wt_to.branch.repository)
565
merge_inner(wt_to.branch, branch_from.basis_tree(),
1228
merge_inner(wt_to.branch, branch_from.basis_tree(),
566
1229
wt_to.branch.repository.revision_tree(base_rev),
567
1230
this_tree=wt_to)
568
wt_to.add_pending_merge(branch_from.last_revision())
1231
wt_to.add_parent_tree_id(branch_from.last_revision())
571
1234
BzrTestBase = TestCase
1237
class TestCaseWithMemoryTransport(TestCase):
1238
"""Common test class for tests that do not need disk resources.
1240
Tests that need disk resources should derive from TestCaseWithTransport.
1242
TestCaseWithMemoryTransport sets the TEST_ROOT variable for all bzr tests.
1244
For TestCaseWithMemoryTransport the test_home_dir is set to the name of
1245
a directory which does not exist. This serves to help ensure test isolation
1246
is preserved. test_dir is set to the TEST_ROOT, as is cwd, because they
1247
must exist. However, TestCaseWithMemoryTransport does not offer local
1248
file defaults for the transport in tests, nor does it obey the command line
1249
override, so tests that accidentally write to the common directory should
1257
def __init__(self, methodName='runTest'):
1258
# allow test parameterisation after test construction and before test
1259
# execution. Variables that the parameteriser sets need to be
1260
# ones that are not set by setUp, or setUp will trash them.
1261
super(TestCaseWithMemoryTransport, self).__init__(methodName)
1262
self.transport_server = default_transport
1263
self.transport_readonly_server = None
1265
def get_transport(self):
1266
"""Return a writeable transport for the test scratch space"""
1267
t = get_transport(self.get_url())
1268
self.assertFalse(t.is_readonly())
1271
def get_readonly_transport(self):
1272
"""Return a readonly transport for the test scratch space
1274
This can be used to test that operations which should only need
1275
readonly access in fact do not try to write.
1277
t = get_transport(self.get_readonly_url())
1278
self.assertTrue(t.is_readonly())
1281
def create_transport_readonly_server(self):
1282
"""Create a transport server from class defined at init.
1284
This is mostly a hook for daughter classes.
1286
return self.transport_readonly_server()
1288
def get_readonly_server(self):
1289
"""Get the server instance for the readonly transport
1291
This is useful for some tests with specific servers to do diagnostics.
1293
if self.__readonly_server is None:
1294
if self.transport_readonly_server is None:
1295
# readonly decorator requested
1296
# bring up the server
1298
self.__readonly_server = ReadonlyServer()
1299
self.__readonly_server.setUp(self.__server)
1301
self.__readonly_server = self.create_transport_readonly_server()
1302
self.__readonly_server.setUp()
1303
self.addCleanup(self.__readonly_server.tearDown)
1304
return self.__readonly_server
1306
def get_readonly_url(self, relpath=None):
1307
"""Get a URL for the readonly transport.
1309
This will either be backed by '.' or a decorator to the transport
1310
used by self.get_url()
1311
relpath provides for clients to get a path relative to the base url.
1312
These should only be downwards relative, not upwards.
1314
base = self.get_readonly_server().get_url()
1315
if relpath is not None:
1316
if not base.endswith('/'):
1318
base = base + relpath
1321
def get_server(self):
1322
"""Get the read/write server instance.
1324
This is useful for some tests with specific servers that need
1327
For TestCaseWithMemoryTransport this is always a MemoryServer, and there
1328
is no means to override it.
1330
if self.__server is None:
1331
self.__server = MemoryServer()
1332
self.__server.setUp()
1333
self.addCleanup(self.__server.tearDown)
1334
return self.__server
1336
def get_url(self, relpath=None):
1337
"""Get a URL (or maybe a path) for the readwrite transport.
1339
This will either be backed by '.' or to an equivalent non-file based
1341
relpath provides for clients to get a path relative to the base url.
1342
These should only be downwards relative, not upwards.
1344
base = self.get_server().get_url()
1345
if relpath is not None and relpath != '.':
1346
if not base.endswith('/'):
1348
# XXX: Really base should be a url; we did after all call
1349
# get_url()! But sometimes it's just a path (from
1350
# LocalAbspathServer), and it'd be wrong to append urlescaped data
1351
# to a non-escaped local path.
1352
if base.startswith('./') or base.startswith('/'):
1355
base += urlutils.escape(relpath)
1358
def _make_test_root(self):
1359
if TestCaseWithMemoryTransport.TEST_ROOT is not None:
1363
root = u'test%04d.tmp' % i
1367
if e.errno == errno.EEXIST:
1372
# successfully created
1373
TestCaseWithMemoryTransport.TEST_ROOT = osutils.abspath(root)
1375
# make a fake bzr directory there to prevent any tests propagating
1376
# up onto the source directory's real branch
1377
bzrdir.BzrDir.create_standalone_workingtree(
1378
TestCaseWithMemoryTransport.TEST_ROOT)
1380
def makeAndChdirToTestDir(self):
1381
"""Create a temporary directories for this one test.
1383
This must set self.test_home_dir and self.test_dir and chdir to
1386
For TestCaseWithMemoryTransport we chdir to the TEST_ROOT for this test.
1388
os.chdir(TestCaseWithMemoryTransport.TEST_ROOT)
1389
self.test_dir = TestCaseWithMemoryTransport.TEST_ROOT
1390
self.test_home_dir = self.test_dir + "/MemoryTransportMissingHomeDir"
1392
def make_branch(self, relpath, format=None):
1393
"""Create a branch on the transport at relpath."""
1394
repo = self.make_repository(relpath, format=format)
1395
return repo.bzrdir.create_branch()
1397
def make_bzrdir(self, relpath, format=None):
1399
# might be a relative or absolute path
1400
maybe_a_url = self.get_url(relpath)
1401
segments = maybe_a_url.rsplit('/', 1)
1402
t = get_transport(maybe_a_url)
1403
if len(segments) > 1 and segments[-1] not in ('', '.'):
1406
except errors.FileExists:
1408
if isinstance(format, basestring):
1409
format = bzrdir.format_registry.make_bzrdir(format)
1410
elif format is None:
1411
format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
1412
return format.initialize_on_transport(t)
1413
except errors.UninitializableFormat:
1414
raise TestSkipped("Format %s is not initializable." % format)
1416
def make_repository(self, relpath, shared=False, format=None):
1417
"""Create a repository on our default transport at relpath."""
1418
made_control = self.make_bzrdir(relpath, format=format)
1419
return made_control.create_repository(shared=shared)
1421
def make_branch_and_memory_tree(self, relpath, format=None):
1422
"""Create a branch on the default transport and a MemoryTree for it."""
1423
b = self.make_branch(relpath, format=format)
1424
return memorytree.MemoryTree.create_on_branch(b)
1426
def overrideEnvironmentForTesting(self):
1427
os.environ['HOME'] = self.test_home_dir
1428
os.environ['APPDATA'] = self.test_home_dir
1431
super(TestCaseWithMemoryTransport, self).setUp()
1432
self._make_test_root()
1433
_currentdir = os.getcwdu()
1434
def _leaveDirectory():
1435
os.chdir(_currentdir)
1436
self.addCleanup(_leaveDirectory)
1437
self.makeAndChdirToTestDir()
1438
self.overrideEnvironmentForTesting()
1439
self.__readonly_server = None
1440
self.__server = None
574
class TestCaseInTempDir(TestCase):
1443
class TestCaseInTempDir(TestCaseWithMemoryTransport):
575
1444
"""Derived class that runs a test within a temporary directory.
577
1446
This is useful for tests that need to create a branch, etc.
662
1510
VFS's. If the transport is readonly or None,
663
1511
"." is opened automatically.
665
# XXX: It's OK to just create them using forward slashes on windows?
1513
# It's OK to just create them using forward slashes on windows.
666
1514
if transport is None or transport.is_readonly():
667
1515
transport = get_transport(".")
668
1516
for name in shape:
669
1517
self.assert_(isinstance(name, basestring))
670
1518
if name[-1] == '/':
671
transport.mkdir(urlescape(name[:-1]))
1519
transport.mkdir(urlutils.escape(name[:-1]))
673
1521
if line_endings == 'binary':
675
1523
elif line_endings == 'native':
676
1524
end = os.linesep
678
raise errors.BzrError('Invalid line ending request %r' % (line_endings,))
679
content = "contents of %s%s" % (name, end)
680
transport.put(urlescape(name), StringIO(content))
1526
raise errors.BzrError(
1527
'Invalid line ending request %r' % line_endings)
1528
content = "contents of %s%s" % (name.encode('utf-8'), end)
1529
transport.put_bytes_non_atomic(urlutils.escape(name), content)
682
1531
def build_tree_contents(self, shape):
683
1532
build_tree_contents(shape)
1534
def assertFileEqual(self, content, path):
1535
"""Fail if path does not contain 'content'."""
1536
self.failUnlessExists(path)
1537
# TODO: jam 20060427 Shouldn't this be 'rb'?
1538
self.assertEqualDiff(content, open(path, 'r').read())
685
1540
def failUnlessExists(self, path):
686
1541
"""Fail unless path, which may be abs or relative, exists."""
687
1542
self.failUnless(osutils.lexists(path))
710
1560
readwrite one must both define get_url() as resolving to os.getcwd().
713
def __init__(self, methodName='testMethod'):
714
super(TestCaseWithTransport, self).__init__(methodName)
715
self.__readonly_server = None
717
self.transport_server = default_transport
718
self.transport_readonly_server = None
720
def get_readonly_url(self, relpath=None):
721
"""Get a URL for the readonly transport.
723
This will either be backed by '.' or a decorator to the transport
724
used by self.get_url()
725
relpath provides for clients to get a path relative to the base url.
726
These should only be downwards relative, not upwards.
728
base = self.get_readonly_server().get_url()
729
if relpath is not None:
730
if not base.endswith('/'):
732
base = base + relpath
735
def get_readonly_server(self):
736
"""Get the server instance for the readonly transport
738
This is useful for some tests with specific servers to do diagnostics.
740
if self.__readonly_server is None:
741
if self.transport_readonly_server is None:
742
# readonly decorator requested
743
# bring up the server
745
self.__readonly_server = ReadonlyServer()
746
self.__readonly_server.setUp(self.__server)
748
self.__readonly_server = self.transport_readonly_server()
749
self.__readonly_server.setUp()
750
self.addCleanup(self.__readonly_server.tearDown)
751
return self.__readonly_server
1563
def create_transport_server(self):
1564
"""Create a transport server from class defined at init.
1566
This is mostly a hook for daughter classes.
1568
return self.transport_server()
753
1570
def get_server(self):
754
"""Get the read/write server instance.
1571
"""See TestCaseWithMemoryTransport.
756
1573
This is useful for some tests with specific servers that need
759
1576
if self.__server is None:
760
self.__server = self.transport_server()
1577
self.__server = self.create_transport_server()
761
1578
self.__server.setUp()
762
1579
self.addCleanup(self.__server.tearDown)
763
1580
return self.__server
765
def get_url(self, relpath=None):
766
"""Get a URL for the readwrite transport.
768
This will either be backed by '.' or to an equivalent non-file based
770
relpath provides for clients to get a path relative to the base url.
771
These should only be downwards relative, not upwards.
773
base = self.get_server().get_url()
774
if relpath is not None and relpath != '.':
775
if not base.endswith('/'):
777
base = base + relpath
780
def get_transport(self):
781
"""Return a writeable transport for the test scratch space"""
782
t = get_transport(self.get_url())
783
self.assertFalse(t.is_readonly())
786
def get_readonly_transport(self):
787
"""Return a readonly transport for the test scratch space
789
This can be used to test that operations which should only need
790
readonly access in fact do not try to write.
792
t = get_transport(self.get_readonly_url())
793
self.assertTrue(t.is_readonly())
796
def make_branch(self, relpath):
797
"""Create a branch on the transport at relpath."""
798
repo = self.make_repository(relpath)
799
return repo.bzrdir.create_branch()
801
def make_bzrdir(self, relpath):
803
url = self.get_url(relpath)
804
segments = relpath.split('/')
805
if segments and segments[-1] not in ('', '.'):
806
parent = self.get_url('/'.join(segments[:-1]))
807
t = get_transport(parent)
809
t.mkdir(segments[-1])
810
except errors.FileExists:
812
return bzrlib.bzrdir.BzrDir.create(url)
813
except errors.UninitializableFormat:
814
raise TestSkipped("Format %s is not initializable.")
816
def make_repository(self, relpath, shared=False):
817
"""Create a repository on our default transport at relpath."""
818
made_control = self.make_bzrdir(relpath)
819
return made_control.create_repository(shared=shared)
821
def make_branch_and_tree(self, relpath):
1582
def make_branch_and_tree(self, relpath, format=None):
822
1583
"""Create a branch on the transport and a tree locally.
1585
If the transport is not a LocalTransport, the Tree can't be created on
1586
the transport. In that case the working tree is created in the local
1587
directory, and the returned tree's branch and repository will also be
1590
This will fail if the original default transport for this test
1591
case wasn't backed by the working directory, as the branch won't
1592
be on disk for us to open it.
1594
:param format: The BzrDirFormat.
1595
:returns: the WorkingTree.
826
1597
# TODO: always use the local disk path for the working tree,
827
1598
# this obviously requires a format that supports branch references
828
1599
# so check for that by checking bzrdir.BzrDirFormat.get_default_format()
830
b = self.make_branch(relpath)
1601
b = self.make_branch(relpath, format=format)
832
1603
return b.bzrdir.create_workingtree()
833
1604
except errors.NotLocalUrl:
834
# new formats - catch No tree error and create
835
# a branch reference and a checkout.
836
# old formats at that point - raise TestSkipped.
838
return WorkingTreeFormat2().initialize(bzrdir.BzrDir.open(relpath))
1605
# We can only make working trees locally at the moment. If the
1606
# transport can't support them, then reopen the branch on a local
1607
# transport, and create the working tree there.
1609
# Possibly we should instead keep
1610
# the non-disk-backed branch and create a local checkout?
1611
bd = bzrdir.BzrDir.open(relpath)
1612
return bd.create_workingtree()
840
1614
def assertIsDirectory(self, relpath, transport):
841
1615
"""Assert that relpath within transport is a directory.
1661
def sort_suite_by_re(suite, pattern):
1664
filter_re = re.compile(pattern)
1665
for test in iter_suite_tests(suite):
1666
if filter_re.search(test.id()):
1670
return TestUtil.TestSuite(first + second)
883
1673
def run_suite(suite, name='test', verbose=False, pattern=".*",
884
1674
stop_on_failure=False, keep_output=False,
886
TestCaseInTempDir._TEST_NAME = name
1675
transport=None, lsprof_timed=None, bench_history=None,
1676
matching_tests_first=None):
1677
TestCase._gather_lsprof_in_benchmarks = lsprof_timed
891
1682
runner = TextTestRunner(stream=sys.stdout,
1684
verbosity=verbosity,
1685
keep_output=keep_output,
1686
bench_history=bench_history)
894
1687
runner.stop_on_failure=stop_on_failure
895
1688
if pattern != '.*':
896
suite = filter_suite_by_re(suite, pattern)
1689
if matching_tests_first:
1690
suite = sort_suite_by_re(suite, pattern)
1692
suite = filter_suite_by_re(suite, pattern)
897
1693
result = runner.run(suite)
898
# This is still a little bogus,
899
# but only a little. Folk not using our testrunner will
900
# have to delete their temp directories themselves.
901
test_root = TestCaseInTempDir.TEST_ROOT
902
if result.wasSuccessful() or not keep_output:
903
if test_root is not None:
904
print 'Deleting test root %s...' % test_root
906
shutil.rmtree(test_root)
910
print "Failed tests working directories are in '%s'\n" % TestCaseInTempDir.TEST_ROOT
911
1694
return result.wasSuccessful()
914
1697
def selftest(verbose=False, pattern=".*", stop_on_failure=True,
915
1698
keep_output=False,
1700
test_suite_factory=None,
1703
matching_tests_first=None):
917
1704
"""Run the whole test suite under the enhanced runner"""
1705
# XXX: Very ugly way to do this...
1706
# Disable warning about old formats because we don't want it to disturb
1707
# any blackbox tests.
1708
from bzrlib import repository
1709
repository._deprecation_warning_done = True
918
1711
global default_transport
919
1712
if transport is None:
920
1713
transport = default_transport
921
1714
old_transport = default_transport
922
1715
default_transport = transport
1717
if test_suite_factory is None:
1718
suite = test_suite()
1720
suite = test_suite_factory()
925
1721
return run_suite(suite, 'testbzr', verbose=verbose, pattern=pattern,
926
1722
stop_on_failure=stop_on_failure, keep_output=keep_output,
1723
transport=transport,
1724
lsprof_timed=lsprof_timed,
1725
bench_history=bench_history,
1726
matching_tests_first=matching_tests_first)
929
1728
default_transport = old_transport
933
1731
def test_suite():
934
"""Build and return TestSuite for the whole program."""
935
from doctest import DocTestSuite
937
global MODULES_TO_DOCTEST
1732
"""Build and return TestSuite for the whole of bzrlib.
1734
This function can be replaced if you need to change the default test
1735
suite on a global basis, but it is not encouraged.
940
1738
'bzrlib.tests.test_ancestry',
941
1739
'bzrlib.tests.test_annotate',
942
1740
'bzrlib.tests.test_api',
1741
'bzrlib.tests.test_atomicfile',
943
1742
'bzrlib.tests.test_bad_files',
944
'bzrlib.tests.test_basis_inventory',
945
1743
'bzrlib.tests.test_branch',
1744
'bzrlib.tests.test_bundle',
946
1745
'bzrlib.tests.test_bzrdir',
947
'bzrlib.tests.test_command',
1746
'bzrlib.tests.test_cache_utf8',
1747
'bzrlib.tests.test_commands',
948
1748
'bzrlib.tests.test_commit',
949
1749
'bzrlib.tests.test_commit_merge',
950
1750
'bzrlib.tests.test_config',
973
1782
'bzrlib.tests.test_nonascii',
974
1783
'bzrlib.tests.test_options',
975
1784
'bzrlib.tests.test_osutils',
1785
'bzrlib.tests.test_osutils_encodings',
1786
'bzrlib.tests.test_patch',
1787
'bzrlib.tests.test_patches',
976
1788
'bzrlib.tests.test_permissions',
977
1789
'bzrlib.tests.test_plugins',
978
1790
'bzrlib.tests.test_progress',
979
1791
'bzrlib.tests.test_reconcile',
1792
'bzrlib.tests.test_registry',
980
1793
'bzrlib.tests.test_repository',
1794
'bzrlib.tests.test_revert',
981
1795
'bzrlib.tests.test_revision',
982
1796
'bzrlib.tests.test_revisionnamespaces',
983
'bzrlib.tests.test_revprops',
1797
'bzrlib.tests.test_revisiontree',
984
1798
'bzrlib.tests.test_rio',
985
1799
'bzrlib.tests.test_sampler',
986
1800
'bzrlib.tests.test_selftest',
987
1801
'bzrlib.tests.test_setup',
988
1802
'bzrlib.tests.test_sftp_transport',
989
1803
'bzrlib.tests.test_smart_add',
1804
'bzrlib.tests.test_smart_transport',
990
1805
'bzrlib.tests.test_source',
1806
'bzrlib.tests.test_status',
991
1807
'bzrlib.tests.test_store',
992
1808
'bzrlib.tests.test_symbol_versioning',
993
1809
'bzrlib.tests.test_testament',
1810
'bzrlib.tests.test_textfile',
1811
'bzrlib.tests.test_textmerge',
994
1812
'bzrlib.tests.test_trace',
995
1813
'bzrlib.tests.test_transactions',
996
1814
'bzrlib.tests.test_transform',
997
1815
'bzrlib.tests.test_transport',
1816
'bzrlib.tests.test_tree',
1817
'bzrlib.tests.test_treebuilder',
998
1818
'bzrlib.tests.test_tsort',
1819
'bzrlib.tests.test_tuned_gzip',
999
1820
'bzrlib.tests.test_ui',
1000
1821
'bzrlib.tests.test_upgrade',
1822
'bzrlib.tests.test_urlutils',
1001
1823
'bzrlib.tests.test_versionedfile',
1824
'bzrlib.tests.test_version',
1825
'bzrlib.tests.test_version_info',
1002
1826
'bzrlib.tests.test_weave',
1003
1827
'bzrlib.tests.test_whitebox',
1004
1828
'bzrlib.tests.test_workingtree',
1829
'bzrlib.tests.test_wsgi',
1005
1830
'bzrlib.tests.test_xml',
1007
1832
test_transport_implementations = [
1008
'bzrlib.tests.test_transport_implementations']
1010
TestCase.BZRPATH = osutils.pathjoin(
1011
osutils.realpath(osutils.dirname(bzrlib.__path__[0])), 'bzr')
1012
print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
1013
print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
1016
# python2.4's TestLoader.loadTestsFromNames gives very poor
1017
# errors if it fails to load a named module - no indication of what's
1018
# actually wrong, just "no such module". We should probably override that
1019
# class, but for the moment just load them ourselves. (mbp 20051202)
1020
loader = TestLoader()
1833
'bzrlib.tests.test_transport_implementations',
1834
'bzrlib.tests.test_read_bundle',
1836
suite = TestUtil.TestSuite()
1837
loader = TestUtil.TestLoader()
1838
suite.addTest(loader.loadTestsFromModuleNames(testmod_names))
1021
1839
from bzrlib.transport import TransportTestProviderAdapter
1022
1840
adapter = TransportTestProviderAdapter()
1023
1841
adapt_modules(test_transport_implementations, adapter, loader, suite)
1024
for mod_name in testmod_names:
1025
mod = _load_module_by_name(mod_name)
1026
suite.addTest(loader.loadTestsFromModule(mod))
1027
1842
for package in packages_to_test():
1028
1843
suite.addTest(package.test_suite())
1029
1844
for m in MODULES_TO_TEST:
1030
1845
suite.addTest(loader.loadTestsFromModule(m))
1031
for m in (MODULES_TO_DOCTEST):
1032
suite.addTest(DocTestSuite(m))
1846
for m in MODULES_TO_DOCTEST:
1848
suite.addTest(doctest.DocTestSuite(m))
1849
except ValueError, e:
1850
print '**failed to get doctest for: %s\n%s' %(m,e)
1033
1852
for name, plugin in bzrlib.plugin.all_plugins().items():
1034
1853
if getattr(plugin, 'test_suite', None) is not None:
1035
1854
suite.addTest(plugin.test_suite())