Rev 4802: Move the passing of test logs to the result to be via the getDetails API and remove all public use of TestCase._get_log. in http://bazaar.launchpad.net/~lifeless/bzr/subunit
Robert Collins
robertc at robertcollins.net
Sun Dec 6 00:13:00 GMT 2009
At http://bazaar.launchpad.net/~lifeless/bzr/subunit
------------------------------------------------------------
revno: 4802
revision-id: robertc at robertcollins.net-20091206001245-x1nv37nkl21xktyy
parent: robertc at robertcollins.net-20091205100734-xobmvk2j4yk8kuvw
committer: Robert Collins <robertc at robertcollins.net>
branch nick: subunit
timestamp: Sun 2009-12-06 11:12:45 +1100
message:
Move the passing of test logs to the result to be via the getDetails API and remove all public use of TestCase._get_log.
=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py 2009-12-05 10:07:34 +0000
+++ b/bzrlib/tests/__init__.py 2009-12-06 00:12:45 +0000
@@ -46,6 +46,7 @@
import tempfile
import threading
import time
+import traceback
import unittest
import warnings
@@ -364,26 +365,6 @@
self.not_applicable_count += 1
self.report_not_applicable(test, reason)
- def printErrorList(self, flavour, errors):
- for test, err in errors:
- self.stream.writeln(self.separator1)
- self.stream.write("%s: " % flavour)
- self.stream.writeln(self.getDescription(test))
- if getattr(test, '_get_log', None) is not None:
- log_contents = test._get_log()
- if log_contents:
- self.stream.write('\n')
- self.stream.write(
- ('vvvv[log from %s]' % test.id()).ljust(78,'-'))
- self.stream.write('\n')
- self.stream.write(log_contents)
- self.stream.write('\n')
- self.stream.write(
- ('^^^^[log from %s]' % test.id()).ljust(78,'-'))
- self.stream.write('\n')
- self.stream.writeln(self.separator2)
- self.stream.writeln("%s" % err)
-
def _post_mortem(self):
"""Start a PDB post mortem session."""
if os.environ.get('BZR_TEST_PDB', None):
@@ -602,6 +583,13 @@
applied left to right - the first element in the list is the
innermost decorator.
"""
+ # stream may know claim to know to write unicode strings, but in older
+ # pythons this goes sufficiently wrong that it is a bad idea. (
+ # specifically a built in file with encoding 'UTF-8' will still try
+ # to encode using ascii.
+ new_encoding = osutils.get_terminal_encoding()
+ stream = codecs.getwriter(new_encoding)(stream)
+ stream.encoding = new_encoding
self.stream = unittest._WritelnDecorator(stream)
self.descriptions = descriptions
self.verbosity = verbosity
@@ -670,6 +658,22 @@
"""
+# traceback._some_str fails to format exceptions that have the default
+# __str__ which does an implicit ascii conversion. However, repr() on those
+# objects works, for all that its not quite what the doctor may have ordered.
+def _clever_some_str(value):
+ try:
+ return str(value)
+ except:
+ try:
+ return repr(value).replace('\\n', '\n')
+ except:
+ return '<unprintable %s object>' % type(value).__name__
+
+traceback._some_str = _clever_some_str
+
+
+
class KnownFailure(AssertionError):
"""Indicates that a test failed in a precisely expected manner.
@@ -798,15 +802,15 @@
(TestNotApplicable, self._do_not_applicable))
self.exception_handlers.insert(0,
(KnownFailure, self._do_known_failure))
+
+ def setUp(self):
+ super(TestCase, self).setUp()
+ for feature in getattr(self, '_test_needs_features', []):
+ self.requireFeature(feature)
self._log_contents = None
self.addDetail("log", content.Content(content.ContentType("text",
"plain", {"charset": "utf8"}),
- lambda:[self._get_log(keep_log_file=True)]))
-
- def setUp(self):
- super(TestCase, self).setUp()
- for feature in getattr(self, '_test_needs_features', []):
- self.requireFeature(feature)
+ lambda:[self._get_log(keep_log_file=True, _utf8=True)]))
self._cleanEnvironment()
self._silenceUI()
self._startLogFile()
@@ -1631,16 +1635,24 @@
def log(self, *args):
mutter(*args)
- def _get_log(self, keep_log_file=False):
+ def _get_log(self, keep_log_file=False, _utf8=False):
"""Get the log from bzrlib.trace calls from this test.
:param keep_log_file: When True, if the log is still a file on disk
leave it as a file on disk. When False, if the log is still a file
on disk, the log file is deleted and the log preserved as
self._log_contents.
+ :param _utf8: Private for the getDetails callback; used to ensure that
+ the returned content is valid utf8.
:return: A string containing the log.
"""
if self._log_contents is not None:
+ if _utf8:
+ try:
+ self._log_contents.decode('utf8')
+ except UnicodeDecodeError:
+ unicodestr = self._log_contents.decode('utf8', 'replace')
+ self._log_contents = unicodestr.encode('utf8')
return self._log_contents
import bzrlib.trace
if bzrlib.trace._trace_file:
@@ -1652,6 +1664,12 @@
log_contents = logfile.read()
finally:
logfile.close()
+ if _utf8:
+ try:
+ log_contents.decode('utf8')
+ except UnicodeDecodeError:
+ unicodestr = log_contents.decode('utf8', 'replace')
+ log_contents = unicodestr.encode('utf8')
if not keep_log_file:
# Permit multiple calls to get_log.
self._log_contents = log_contents
@@ -3075,7 +3093,7 @@
if self.randomised:
return iter(self._tests)
self.randomised = True
- self.stream.writeln("Randomizing test order using seed %s\n" %
+ self.stream.write("Randomizing test order using seed %s\n" %
(self.actual_seed()))
# Initialise the random number generator.
random.seed(self.actual_seed())
=== modified file 'bzrlib/tests/blackbox/test_debug.py'
--- a/bzrlib/tests/blackbox/test_debug.py 2009-03-23 14:59:43 +0000
+++ b/bzrlib/tests/blackbox/test_debug.py 2009-12-06 00:12:45 +0000
@@ -38,5 +38,5 @@
def test_dash_dlock(self):
# With -Dlock, locking and unlocking is recorded into the log
self.run_bzr("-Dlock init foo")
- trace_messages = self._get_log(keep_log_file=True)
- self.assertContainsRe(trace_messages, "lock_write")
+ log = u"".join(self.getDetails()['log'].iter_text())
+ self.assertContainsRe(log, "lock_write")
=== modified file 'bzrlib/tests/blackbox/test_exceptions.py'
--- a/bzrlib/tests/blackbox/test_exceptions.py 2009-08-20 06:25:02 +0000
+++ b/bzrlib/tests/blackbox/test_exceptions.py 2009-12-06 00:12:45 +0000
@@ -55,8 +55,8 @@
os.mkdir('foo')
bzrdir.BzrDirFormat5().initialize('foo')
out, err = self.run_bzr("status foo")
- self.assertContainsRe(self._get_log(keep_log_file=True),
- "bzr upgrade")
+ log = u"".join(self.getDetails()['log'].iter_text())
+ self.assertContainsRe(log, "bzr upgrade")
finally:
repository._deprecation_warning_done = True
=== modified file 'bzrlib/tests/per_pack_repository.py'
--- a/bzrlib/tests/per_pack_repository.py 2009-09-07 03:35:06 +0000
+++ b/bzrlib/tests/per_pack_repository.py 2009-12-06 00:12:45 +0000
@@ -687,9 +687,9 @@
# abort_write_group will not raise an error
self.assertEqual(None, repo.abort_write_group(suppress_errors=True))
# But it does log an error
- log_file = self._get_log(keep_log_file=True)
- self.assertContainsRe(log_file, 'abort_write_group failed')
- self.assertContainsRe(log_file, r'INFO bzr: ERROR \(ignored\):')
+ log = u"".join(self.getDetails()['log'].iter_text())
+ self.assertContainsRe(log, 'abort_write_group failed')
+ self.assertContainsRe(log, r'INFO bzr: ERROR \(ignored\):')
if token is not None:
repo.leave_lock_in_place()
=== modified file 'bzrlib/tests/per_repository/test_check.py'
--- a/bzrlib/tests/per_repository/test_check.py 2009-08-30 23:51:10 +0000
+++ b/bzrlib/tests/per_repository/test_check.py 2009-12-06 00:12:45 +0000
@@ -46,7 +46,7 @@
revid2 = tree.commit('2')
check_object = tree.branch.repository.check([revid1, revid2])
check_object.report_results(verbose=True)
- log = self._get_log(keep_log_file=True)
+ log = u"".join(self.getDetails()['log'].iter_text())
self.assertContainsRe(log, "0 unreferenced text versions")
@@ -90,11 +90,11 @@
# contents of it!
check_object = repo.check(['ignored'])
check_object.report_results(verbose=False)
- log = self._get_log(keep_log_file=True)
+ log = u"".join(self.getDetails()['log'].iter_text())
self.assertContainsRe(
log, '1 revisions have incorrect parents in the revision index')
check_object.report_results(verbose=True)
- log = self._get_log(keep_log_file=True)
+ log = u"".join(self.getDetails()['log'].iter_text())
self.assertContainsRe(
log,
"revision-id has wrong parents in index: "
@@ -147,5 +147,5 @@
rev_id = builder.commit('first post')
result = repo.check(None, check_repo=True)
result.report_results(True)
- log = self._get_log(keep_log_file=True)
+ log = u"".join(self.getDetails()['log'].iter_text())
self.assertFalse('Missing' in log, "Something was missing in %r" % log)
=== modified file 'bzrlib/tests/per_repository/test_check_reconcile.py'
--- a/bzrlib/tests/per_repository/test_check_reconcile.py 2009-03-23 14:59:43 +0000
+++ b/bzrlib/tests/per_repository/test_check_reconcile.py 2009-12-06 00:12:45 +0000
@@ -198,10 +198,9 @@
repo, scenario = self.prepare_test_repository()
check_result = repo.check()
check_result.report_results(verbose=True)
+ log = u"".join(self.getDetails()['log'].iter_text())
for pattern in scenario.check_regexes(repo):
- self.assertContainsRe(
- self._get_log(keep_log_file=True),
- pattern)
+ self.assertContainsRe(log, pattern)
def test_find_text_key_references(self):
"""Test that find_text_key_references finds erroneous references."""
=== modified file 'bzrlib/tests/per_repository_reference/test_check.py'
--- a/bzrlib/tests/per_repository_reference/test_check.py 2009-08-11 05:26:57 +0000
+++ b/bzrlib/tests/per_repository_reference/test_check.py 2009-12-06 00:12:45 +0000
@@ -39,5 +39,5 @@
check_result = referring.branch.repository.check(
referring.branch.repository.all_revision_ids())
check_result.report_results(verbose=False)
- log = self._get_log(keep_log_file=True)
+ log = u"".join(self.getDetails()['log'].iter_text())
self.assertFalse("inconsistent parents" in log)
=== modified file 'bzrlib/tests/test_cleanup.py'
--- a/bzrlib/tests/test_cleanup.py 2009-10-26 06:23:14 +0000
+++ b/bzrlib/tests/test_cleanup.py 2009-12-06 00:12:45 +0000
@@ -39,7 +39,7 @@
self.call_log.append('no_op_cleanup')
def assertLogContains(self, regex):
- log = self._get_log(keep_log_file=True)
+ log = u"".join(self.getDetails()['log'].iter_text())
self.assertContainsRe(log, regex, re.DOTALL)
def failing_cleanup(self):
@@ -184,7 +184,7 @@
self.assertRaises(ErrorA, _do_with_cleanups, cleanups,
self.trivial_func)
self.assertLogContains('Cleanup failed:.*ErrorB')
- log = self._get_log(keep_log_file=True)
+ log = u"".join(self.getDetails()['log'].iter_text())
self.assertFalse('ErrorA' in log)
def make_two_failing_cleanup_funcs(self):
=== modified file 'bzrlib/tests/test_config.py'
--- a/bzrlib/tests/test_config.py 2009-08-20 04:53:23 +0000
+++ b/bzrlib/tests/test_config.py 2009-12-06 00:12:45 +0000
@@ -1573,8 +1573,9 @@
# the user is prompted
self.assertEquals(entered_password,
conf.get_password('ssh', 'bar.org', user='jim'))
+ log = u"".join(self.getDetails()['log'].iter_text())
self.assertContainsRe(
- self._get_log(keep_log_file=True),
+ log,
'password ignored in section \[ssh with password\]')
def test_ssh_without_password_doesnt_emit_warning(self):
@@ -1598,8 +1599,9 @@
conf.get_password('ssh', 'bar.org', user='jim'))
# No warning shoud be emitted since there is no password. We are only
# providing "user".
+ log = u"".join(self.getDetails()['log'].iter_text())
self.assertNotContainsRe(
- self._get_log(keep_log_file=True),
+ log,
'password ignored in section \[ssh with password\]')
def test_uses_fallback_stores(self):
=== modified file 'bzrlib/tests/test_http_response.py'
--- a/bzrlib/tests/test_http_response.py 2009-03-23 14:59:43 +0000
+++ b/bzrlib/tests/test_http_response.py 2009-12-06 00:12:45 +0000
@@ -96,8 +96,8 @@
# Override the thresold to force the warning emission
conn._range_warning_thresold = 6 # There are 7 bytes pending
conn.cleanup_pipe()
- self.assertContainsRe(self._get_log(keep_log_file=True),
- 'Got a 200 response when asking')
+ log = u"".join(self.getDetails()['log'].iter_text())
+ self.assertContainsRe(log, 'Got a 200 response when asking')
class TestRangeFileMixin(object):
=== modified file 'bzrlib/tests/test_merge.py'
--- a/bzrlib/tests/test_merge.py 2009-09-19 00:32:14 +0000
+++ b/bzrlib/tests/test_merge.py 2009-12-06 00:12:45 +0000
@@ -151,12 +151,12 @@
log = StringIO()
merge_inner(tree_b.branch, tree_a, tree_b.basis_tree(),
this_tree=tree_b, ignore_zero=True)
- log = self._get_log(keep_log_file=True)
+ log = u"".join(self.getDetails()['log'].iter_text())
self.failUnless('All changes applied successfully.\n' not in log)
tree_b.revert()
merge_inner(tree_b.branch, tree_a, tree_b.basis_tree(),
this_tree=tree_b, ignore_zero=False)
- log = self._get_log(keep_log_file=True)
+ log = u"".join(self.getDetails()['log'].iter_text())
self.failUnless('All changes applied successfully.\n' in log)
def test_merge_inner_conflicts(self):
=== modified file 'bzrlib/tests/test_remote.py'
--- a/bzrlib/tests/test_remote.py 2009-11-11 06:50:40 +0000
+++ b/bzrlib/tests/test_remote.py 2009-12-06 00:12:45 +0000
@@ -2892,8 +2892,9 @@
self.assertEqual(server_error, translated_error)
# In addition to re-raising ErrorFromSmartServer, some debug info has
# been muttered to the log file for developer to look at.
+ log = u"".join(self.getDetails()['log'].iter_text())
self.assertContainsRe(
- self._get_log(keep_log_file=True),
+ log,
"Missing key 'branch' in context")
def test_path_missing(self):
@@ -2907,8 +2908,8 @@
self.assertEqual(server_error, translated_error)
# In addition to re-raising ErrorFromSmartServer, some debug info has
# been muttered to the log file for developer to look at.
- self.assertContainsRe(
- self._get_log(keep_log_file=True), "Missing key 'path' in context")
+ log = u"".join(self.getDetails()['log'].iter_text())
+ self.assertContainsRe(log, "Missing key 'path' in context")
class TestStacking(tests.TestCaseWithTransport):
=== modified file 'bzrlib/tests/test_trace.py'
--- a/bzrlib/tests/test_trace.py 2009-09-03 02:59:56 +0000
+++ b/bzrlib/tests/test_trace.py 2009-12-06 00:12:45 +0000
@@ -140,21 +140,21 @@
def test_trace_unicode(self):
"""Write Unicode to trace log"""
self.log(u'the unicode character for benzene is \N{BENZENE RING}')
- self.assertContainsRe(self._get_log(keep_log_file=True),
- "the unicode character for benzene is")
+ log = u"".join(self.getDetails()['log'].iter_text())
+ self.assertContainsRe(log, "the unicode character for benzene is")
def test_trace_argument_unicode(self):
"""Write a Unicode argument to the trace log"""
mutter(u'the unicode character for benzene is %s', u'\N{BENZENE RING}')
- self.assertContainsRe(self._get_log(keep_log_file=True),
- 'the unicode character')
+ log = u"".join(self.getDetails()['log'].iter_text())
+ self.assertContainsRe(log, 'the unicode character')
def test_trace_argument_utf8(self):
"""Write a Unicode argument to the trace log"""
mutter(u'the unicode character for benzene is %s',
u'\N{BENZENE RING}'.encode('utf-8'))
- self.assertContainsRe(self._get_log(keep_log_file=True),
- 'the unicode character')
+ log = u"".join(self.getDetails()['log'].iter_text())
+ self.assertContainsRe(log, 'the unicode character')
def test_report_broken_pipe(self):
try:
@@ -173,7 +173,7 @@
def test_mutter_callsite_1(self):
"""mutter_callsite can capture 1 level of stack frame."""
mutter_callsite(1, "foo %s", "a string")
- log = self._get_log(keep_log_file=True)
+ log = u"".join(self.getDetails()['log'].iter_text())
# begin with the message
self.assertLogStartsWith(log, 'foo a string\nCalled from:\n')
# should show two frame: this frame and the one above
@@ -185,7 +185,7 @@
def test_mutter_callsite_2(self):
"""mutter_callsite can capture 2 levels of stack frame."""
mutter_callsite(2, "foo %s", "a string")
- log = self._get_log(keep_log_file=True)
+ log = u"".join(self.getDetails()['log'].iter_text())
# begin with the message
self.assertLogStartsWith(log, 'foo a string\nCalled from:\n')
# should show two frame: this frame and the one above
@@ -197,13 +197,19 @@
def test_mutter_never_fails(self):
# Even if the decode/encode stage fails, mutter should not
# raise an exception
+ # This test checks that mutter doesn't fail; the current behaviour
+ # is that it doesn't fail *and writes non-utf8*.
mutter(u'Writing a greek mu (\xb5) works in a unicode string')
mutter('But fails in an ascii string \xb5')
mutter('and in an ascii argument: %s', '\xb5')
- log = self._get_log(keep_log_file=True)
+ log = u"".join(self.getDetails()['log'].iter_text())
self.assertContainsRe(log, 'Writing a greek mu')
self.assertContainsRe(log, "But fails in an ascii string")
- self.assertContainsRe(log, u"ascii argument: \xb5")
+ # However, the log content object does unicode replacement on reading
+ # to let it get unicode back where good data has been written. So we
+ # have to do a replaceent here as well.
+ self.assertContainsRe(log, "ascii argument: \xb5".decode('utf8',
+ 'replace'))
def test_push_log_file(self):
"""Can push and pop log file, and this catches mutter messages.
=== modified file 'bzrlib/tests/test_transport_log.py'
--- a/bzrlib/tests/test_transport_log.py 2009-07-01 07:04:47 +0000
+++ b/bzrlib/tests/test_transport_log.py 2009-12-06 00:12:45 +0000
@@ -36,10 +36,9 @@
# operations such as mkdir are logged
mutter('where are you?')
logging_transport.mkdir('subdir')
- self.assertContainsRe(self._get_log(True),
- r'mkdir memory\+\d+://.*subdir')
- self.assertContainsRe(self._get_log(True),
- ' --> None')
+ log = u"".join(self.getDetails()['log'].iter_text())
+ self.assertContainsRe(log, r'mkdir memory\+\d+://.*subdir')
+ self.assertContainsRe(log, ' --> None')
# they have the expected effect
self.assertTrue(logging_transport.has('subdir'))
# and they operate on the underlying transport
More information about the bazaar-commits
mailing list