34
from . import features, TestCaseInTempDir, TestCase, TestSkipped
33
from ..sixish import (
37
from . import features, TestCaseInTempDir, TestCase
35
38
from ..trace import (
36
39
mutter, mutter_callsite, report_exception,
37
40
set_verbosity_level, get_verbosity_level, is_quiet, is_verbose, be_quiet,
61
64
except NotImplementedError:
62
65
err = _format_exception()
63
66
self.assertContainsRe(err,
64
'^brz: ERROR: NotImplementedError: time travel')
67
'^brz: ERROR: NotImplementedError: time travel')
65
68
self.assertContainsRe(err,
66
'Bazaar has encountered an internal error.')
69
'Bazaar has encountered an internal error.')
68
71
def test_format_interrupt_exception(self):
109
111
msg = _format_exception()
110
112
# Even though Windows and Linux differ for 'os.rmdir', they both give
111
113
# 'No such file' for open()
112
# However it now gets translated so we can not test for a specific
114
# However it now gets translated so we can not test for a specific message
114
115
self.assertContainsRe(msg,
115
'^brz: ERROR: \\[Errno .*\\] .*nosuchfile')
116
'^brz: ERROR: \\[Errno .*\\] .*nosuchfile')
117
118
def test_format_pywintypes_error(self):
118
119
self.requireFeature(features.pywintypes)
120
import pywintypes, win32file
122
122
win32file.RemoveDirectory('nosuchfile22222')
123
123
except pywintypes.error:
124
124
msg = _format_exception()
125
125
# GZ 2010-05-03: Formatting for pywintypes.error is basic, a 3-tuple
126
126
# with errno, function name, and locale error message
127
self.assertContainsRe(
128
msg, "^brz: ERROR: \\(2, 'RemoveDirectory[AW]?', .*\\)")
127
self.assertContainsRe(msg,
128
"^brz: ERROR: \\(2, 'RemoveDirectory[AW]?', .*\\)")
130
130
def test_format_sockets_error(self):
136
136
msg = _format_exception()
138
138
self.assertNotContainsRe(msg,
139
"Traceback \\(most recent call last\\):")
139
"Traceback \\(most recent call last\\):")
141
141
def test_format_unicode_error(self):
143
raise errors.CommandError(u'argument foo\xb5 does not exist')
144
except errors.CommandError:
143
raise errors.BzrCommandError(u'argument foo\xb5 does not exist')
144
except errors.BzrCommandError:
145
145
msg = _format_exception()
146
expected = 'brz: ERROR: argument foo\xb5 does not exist\n'
147
expected = 'brz: ERROR: argument foo\xb5 does not exist\n'
149
# GZ 2017-06-10: Pretty bogus, should encode per the output stream
150
expected = 'brz: ERROR: argument foo\xc2\xb5 does not exist\n'
147
151
self.assertEqual(msg, expected)
149
153
def test_format_exception(self):
158
162
"""Short friendly message for missing system modules."""
160
164
import ImaginaryModule
165
except ImportError as e:
162
166
msg = _format_exception()
164
168
self.fail("somehow succeeded in importing %r" % ImaginaryModule)
165
self.assertContainsRe(
169
self.assertContainsRe(msg,
167
170
"^brz: ERROR: No module named '?ImaginaryModule'?\n"
168
171
"You may need to install this Python library separately.\n$")
170
173
def test_report_import_syntax_error(self):
172
175
raise ImportError("syntax error")
176
except ImportError as e:
174
177
msg = _format_exception()
175
178
self.assertContainsRe(msg,
176
'Bazaar has encountered an internal error')
179
'Bazaar has encountered an internal error')
178
181
def test_trace_unicode(self):
179
182
"""Write Unicode to trace log"""
194
197
log = self.get_log()
195
198
self.assertContainsRe(log, 'the unicode character')
197
def test_trace_argument_exception(self):
198
err = Exception('an error')
199
mutter(u'can format stringable classes %s', err)
201
self.assertContainsRe(log, 'can format stringable classes an error')
203
200
def test_report_broken_pipe(self):
205
202
raise IOError(errno.EPIPE, 'broken pipe foofofo')
207
204
msg = _format_exception()
208
205
self.assertEqual(msg, "brz: broken pipe\n")
213
210
"""Assert log contains a line including log timestamp."""
214
211
# Does not check absolute position in log as there may be kipple.
215
212
self.assertContainsRe(log,
216
'(?m)^\\d+\\.\\d+ ' + re.escape(string))
213
'(?m)^\\d+\\.\\d+ ' + re.escape(string))
218
215
def test_mutter_callsite_1(self):
219
216
"""mutter_callsite can capture 1 level of stack frame."""
222
219
# begin with the message
223
220
self.assertLogContainsLine(log, 'foo a string\nCalled from:\n')
224
221
# should show two frame: this frame and the one above
225
self.assertContainsRe(
226
log, 'test_trace\\.py", line \\d+, in test_mutter_callsite_1\n')
222
self.assertContainsRe(log,
223
'test_trace\\.py", line \\d+, in test_mutter_callsite_1\n')
227
224
# this frame should be the final one
228
225
self.assertEndsWith(log, ' "a string")\n')
234
231
# begin with the message
235
232
self.assertLogContainsLine(log, 'foo a string\nCalled from:\n')
236
233
# should show two frame: this frame and the one above
237
self.assertContainsRe(
238
log, 'test_trace.py", line \\d+, in test_mutter_callsite_2\n')
234
self.assertContainsRe(log,
235
'test_trace.py", line \d+, in test_mutter_callsite_2\n')
239
236
# this frame should be the final one
240
237
self.assertEndsWith(log, ' "a string")\n')
242
239
def test_mutter_never_fails(self):
243
"""Even with unencodable input mutter should not raise errors."""
244
mutter(u'can write unicode \xa7')
245
mutter('can interpolate unicode %s', u'\xa7')
246
mutter(b'can write bytes \xa7')
247
mutter('can repr bytes %r', b'\xa7')
248
mutter('can interpolate bytes %s', b'\xa7')
249
# Log will always be written as utf-8
240
# Even if the decode/encode stage fails, mutter should not
242
# This test checks that mutter doesn't fail; the current behaviour
243
# is that it doesn't fail *and writes non-utf8*.
244
mutter(u'Writing a greek mu (\xb5) works in a unicode string')
245
mutter(b'But fails in an ascii string \xb5')
246
mutter(b'and in an ascii argument: %s', b'\xb5')
250
247
log = self.get_log()
251
self.assertContainsRe(
253
u'.* +can write unicode \xa7\n'
254
u'.* +can interpolate unicode \xa7\n'
255
u'.* +can write bytes \ufffd\n'
256
u'.* +can repr bytes b\'\\\\xa7\'\n'
257
u'.* +can interpolate bytes (?:\ufffd|b\'\\\\xa7\')\n')
248
self.assertContainsRe(log, 'Writing a greek mu')
249
self.assertContainsRe(log, "But fails in an ascii string")
250
# However, the log content object does unicode replacement on reading
251
# to let it get unicode back where good data has been written. So we
252
# have to do a replaceent here as well.
253
self.assertContainsRe(log, b"ascii argument: \xb5".decode('utf8',
259
256
def test_show_error(self):
260
257
show_error('error1')
261
258
show_error(u'error2 \xb5 blah')
262
259
show_error('arg: %s', 'blah')
263
show_error('arg2: %(key)s', {'key': 'stuff'})
260
show_error('arg2: %(key)s', {'key':'stuff'})
265
262
raise Exception("oops")
266
except BaseException:
267
264
show_error('kwarg', exc_info=True)
268
265
log = self.get_log()
269
266
self.assertContainsRe(log, 'error1')
272
269
self.assertContainsRe(log, 'arg2: stuff')
273
270
self.assertContainsRe(log, 'kwarg')
274
271
self.assertContainsRe(log, 'Traceback \\(most recent call last\\):')
275
self.assertContainsRe(
276
log, 'File ".*test_trace.py", line .*, in test_show_error')
272
self.assertContainsRe(log, 'File ".*test_trace.py", line .*, in test_show_error')
277
273
self.assertContainsRe(log, 'raise Exception\\("oops"\\)')
278
274
self.assertContainsRe(log, 'Exception: oops')
302
298
# as there's a timestamp at the front.
304
300
self.assertContainsRe(tmp1.read(),
305
b"\\d+\\.\\d+ comment to file1\n"
306
b"\\d+\\.\\d+ again to file1\n")
301
b"\\d+\\.\\d+ comment to file1\n"
302
b"\\d+\\.\\d+ again to file1\n")
308
304
self.assertContainsRe(tmp2.read(),
309
b"\\d+\\.\\d+ comment to file2\n")
305
b"\\d+\\.\\d+ comment to file2\n")
320
316
self.overrideEnv('BRZ_LOG', '/no-such-dir/brz.log')
321
317
self.overrideAttr(trace, '_brz_log_filename')
322
318
logf = trace._open_brz_log()
323
if os.path.isdir('/no-such-dir'):
324
raise TestSkipped('directory creation succeeded')
325
319
self.assertIs(None, logf)
326
320
self.assertContainsRe(
327
321
sys.stderr.getvalue(),
328
322
"failed to open trace file: .* '/no-such-dir/brz.log'$")
330
def test__open_brz_log_ignores_cache_dir_error(self):
331
# If the cache directory can not be created and _open_brz_log can thus
332
# not open the file, then we should write the warning to stderr. Since
333
# this is normally happening before logging is set up.
334
self.overrideAttr(sys, 'stderr', StringIO())
335
# Set the cache directory to something that cannot exist
336
self.overrideEnv('BRZ_LOG', None)
337
self.overrideEnv('BRZ_HOME', '/no-such-dir')
338
self.overrideEnv('XDG_CACHE_HOME', '/no-such-dir')
339
self.overrideAttr(trace, '_brz_log_filename')
340
logf = trace._open_brz_log()
341
if os.path.isdir('/no-such-dir'):
342
raise TestSkipped('directory creation succeeded')
343
self.assertIs(None, logf)
344
self.assertContainsRe(
345
sys.stderr.getvalue(),
346
"failed to open trace file: .* '/no-such-dir'$")
349
325
class TestVerbosityLevel(TestCase):
404
380
def test_log_utf8_arg(self):
405
381
logging.getLogger("brz").debug(b"%s", b"\xc2\xa7")
406
expected = u" DEBUG b'\\xc2\\xa7'\n"
383
expected = u" DEBUG b'\\xc2\\xa7'\n"
385
expected = u" DEBUG \xa7\n"
407
386
self.assertEqual(expected, self.get_log())
409
388
def test_log_bytes_msg(self):
410
389
logging.getLogger("brz").debug(b"\xa7")
411
390
log = self.get_log()
412
391
self.assertContainsString(log, "UnicodeDecodeError: ")
413
self.assertContainsRe(
414
log, "Logging record unformattable: b?'\\\\xa7' % \\(\\)\n")
392
self.assertContainsRe(log,
393
"Logging record unformattable: b?'\\\\xa7' % \\(\\)\n")
416
395
def test_log_bytes_arg(self):
417
396
logging.getLogger("brz").debug(b"%s", b"\xa7")
418
397
log = self.get_log()
419
self.assertEqual(u" DEBUG b'\\xa7'\n", self.get_log())
399
self.assertEqual(u" DEBUG b'\\xa7'\n", self.get_log())
401
self.assertContainsString(log, "UnicodeDecodeError: ")
402
self.assertContainsRe(log,
403
"Logging record unformattable: ?'%s' % \\(b?'\\\\xa7',\\)\n")
421
405
def test_log_mixed_strings(self):
422
406
logging.getLogger("brz").debug(u"%s", b"\xa7")
423
407
log = self.get_log()
424
self.assertEqual(u" DEBUG b'\\xa7'\n", self.get_log())
409
self.assertEqual(u" DEBUG b'\\xa7'\n", self.get_log())
411
self.assertContainsString(log, "UnicodeDecodeError: ")
412
self.assertContainsRe(log,
413
"Logging record unformattable: u'%s' % \\('\\\\xa7',\\)\n")
426
415
def test_log_repr_broken(self):
427
416
class BadRepr(object):