/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/tests/test_trace.py

  • Committer: Jelmer Vernooij
  • Date: 2017-06-08 23:30:31 UTC
  • mto: This revision was merged to the branch mainline in revision 6690.
  • Revision ID: jelmer@jelmer.uk-20170608233031-3qavls2o7a1pqllj
Update imports.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
"""Tests for trace library"""
20
20
 
21
21
import errno
22
 
from io import StringIO
23
22
import logging
24
23
import os
25
24
import re
31
30
    errors,
32
31
    trace,
33
32
    )
34
 
from . import features, TestCaseInTempDir, TestCase, TestSkipped
 
33
from ..sixish import (
 
34
    BytesIO,
 
35
    )
 
36
from . import features, TestCaseInTempDir, TestCase
35
37
from ..trace import (
36
38
    mutter, mutter_callsite, report_exception,
37
39
    set_verbosity_level, get_verbosity_level, is_quiet, is_verbose, be_quiet,
44
46
 
45
47
def _format_exception():
46
48
    """Format an exception as it would normally be displayed to the user"""
47
 
    buf = StringIO()
 
49
    buf = BytesIO()
48
50
    report_exception(sys.exc_info(), buf)
49
51
    return buf.getvalue()
50
52
 
59
61
        try:
60
62
            raise NotImplementedError("time travel")
61
63
        except NotImplementedError:
62
 
            err = _format_exception()
63
 
        self.assertContainsRe(err,
64
 
                              '^brz: ERROR: NotImplementedError: time travel')
65
 
        self.assertContainsRe(err,
66
 
                              'Bazaar has encountered an internal error.')
 
64
            pass
 
65
        err = _format_exception()
 
66
        self.assertEqualDiff(err.splitlines()[0],
 
67
                'brz: ERROR: exceptions.NotImplementedError: time travel')
 
68
        self.assertContainsRe(err,
 
69
            'Bazaar has encountered an internal error.')
67
70
 
68
71
    def test_format_interrupt_exception(self):
69
72
        try:
70
73
            raise KeyboardInterrupt()
71
74
        except KeyboardInterrupt:
72
75
            # XXX: Some risk that a *real* keyboard interrupt won't be seen
73
 
            msg = _format_exception()
74
 
        self.assertEqual(msg, 'brz: interrupted\n')
 
76
            pass
 
77
        msg = _format_exception()
 
78
        self.assertTrue(len(msg) > 0)
 
79
        self.assertEqualDiff(msg, 'brz: interrupted\n')
75
80
 
76
81
    def test_format_memory_error(self):
77
82
        try:
78
83
            raise MemoryError()
79
84
        except MemoryError:
80
 
            msg = _format_exception()
81
 
        self.assertEqual(
82
 
            msg,
 
85
            pass
 
86
        msg = _format_exception()
 
87
        self.assertEqual(msg,
83
88
            "brz: out of memory\nUse -Dmem_dump to dump memory to a file.\n")
84
89
 
85
90
    def test_format_mem_dump(self):
88
93
        try:
89
94
            raise MemoryError()
90
95
        except MemoryError:
91
 
            msg = _format_exception()
 
96
            pass
 
97
        msg = _format_exception()
92
98
        self.assertStartsWith(msg,
93
 
                              "brz: out of memory\nMemory dumped to ")
 
99
            "brz: out of memory\nMemory dumped to ")
94
100
 
95
101
    def test_format_os_error(self):
96
102
        try:
97
103
            os.rmdir('nosuchfile22222')
98
104
        except OSError as e:
99
105
            e_str = str(e)
100
 
            msg = _format_exception()
 
106
        msg = _format_exception()
101
107
        # Linux seems to give "No such file" but Windows gives "The system
102
108
        # cannot find the file specified".
103
109
        self.assertEqual('brz: ERROR: %s\n' % (e_str,), msg)
104
110
 
105
111
    def test_format_io_error(self):
106
112
        try:
107
 
            open('nosuchfile22222')
 
113
            file('nosuchfile22222')
108
114
        except IOError:
109
 
            msg = _format_exception()
 
115
            pass
 
116
        msg = _format_exception()
110
117
        # Even though Windows and Linux differ for 'os.rmdir', they both give
111
118
        # 'No such file' for open()
112
 
        # However it now gets translated so we can not test for a specific
113
 
        # message
 
119
        # However it now gets translated so we can not test for a specific message
114
120
        self.assertContainsRe(msg,
115
 
                              '^brz: ERROR: \\[Errno .*\\] .*nosuchfile')
 
121
            r'^brz: ERROR: \[Errno .*\] .*nosuchfile')
116
122
 
117
123
    def test_format_pywintypes_error(self):
118
124
        self.requireFeature(features.pywintypes)
119
 
        import pywintypes
120
 
        import win32file
 
125
        import pywintypes, win32file
121
126
        try:
122
127
            win32file.RemoveDirectory('nosuchfile22222')
123
128
        except pywintypes.error:
124
 
            msg = _format_exception()
 
129
            pass
 
130
        msg = _format_exception()
125
131
        # GZ 2010-05-03: Formatting for pywintypes.error is basic, a 3-tuple
126
132
        #                with errno, function name, and locale error message
127
 
        self.assertContainsRe(
128
 
            msg, "^brz: ERROR: \\(2, 'RemoveDirectory[AW]?', .*\\)")
129
 
 
 
133
        self.assertContainsRe(msg,
 
134
            r"^brz: ERROR: \(2, 'RemoveDirectory[AW]?', .*\)")
 
135
            
130
136
    def test_format_sockets_error(self):
131
137
        try:
132
138
            import socket
133
139
            sock = socket.socket()
134
 
            sock.send(b"This should fail.")
 
140
            sock.send("This should fail.")
135
141
        except socket.error:
136
 
            msg = _format_exception()
137
 
 
 
142
            pass
 
143
        msg = _format_exception()
 
144
        
138
145
        self.assertNotContainsRe(msg,
139
 
                                 "Traceback \\(most recent call last\\):")
 
146
            r"Traceback (most recent call last):")
140
147
 
141
148
    def test_format_unicode_error(self):
142
149
        try:
143
 
            raise errors.CommandError(u'argument foo\xb5 does not exist')
144
 
        except errors.CommandError:
145
 
            msg = _format_exception()
146
 
        expected = 'brz: ERROR: argument foo\xb5 does not exist\n'
147
 
        self.assertEqual(msg, expected)
 
150
            raise errors.BzrCommandError(u'argument foo\xb5 does not exist')
 
151
        except errors.BzrCommandError:
 
152
            pass
 
153
        msg = _format_exception()
148
154
 
149
155
    def test_format_exception(self):
150
156
        """Short formatting of brz exceptions"""
151
157
        try:
152
158
            raise errors.NotBranchError('wibble')
153
159
        except errors.NotBranchError:
154
 
            msg = _format_exception()
155
 
        self.assertEqual(msg, 'brz: ERROR: Not a branch: \"wibble\".\n')
 
160
            pass
 
161
        msg = _format_exception()
 
162
        self.assertTrue(len(msg) > 0)
 
163
        self.assertEqualDiff(msg, 'brz: ERROR: Not a branch: \"wibble\".\n')
156
164
 
157
165
    def test_report_external_import_error(self):
158
166
        """Short friendly message for missing system modules."""
159
167
        try:
160
168
            import ImaginaryModule
161
 
        except ImportError:
162
 
            msg = _format_exception()
 
169
        except ImportError as e:
 
170
            pass
163
171
        else:
164
172
            self.fail("somehow succeeded in importing %r" % ImaginaryModule)
165
 
        self.assertContainsRe(
166
 
            msg,
167
 
            "^brz: ERROR: No module named '?ImaginaryModule'?\n"
168
 
            "You may need to install this Python library separately.\n$")
 
173
        msg = _format_exception()
 
174
        self.assertEqual(msg,
 
175
            'brz: ERROR: No module named ImaginaryModule\n'
 
176
            'You may need to install this Python library separately.\n')
169
177
 
170
178
    def test_report_import_syntax_error(self):
171
179
        try:
172
180
            raise ImportError("syntax error")
173
 
        except ImportError:
174
 
            msg = _format_exception()
 
181
        except ImportError as e:
 
182
            pass
 
183
        msg = _format_exception()
175
184
        self.assertContainsRe(msg,
176
 
                              'Bazaar has encountered an internal error')
 
185
            r'Bazaar has encountered an internal error')
177
186
 
178
187
    def test_trace_unicode(self):
179
188
        """Write Unicode to trace log"""
194
203
        log = self.get_log()
195
204
        self.assertContainsRe(log, 'the unicode character')
196
205
 
197
 
    def test_trace_argument_exception(self):
198
 
        err = Exception('an error')
199
 
        mutter(u'can format stringable classes %s', err)
200
 
        log = self.get_log()
201
 
        self.assertContainsRe(log, 'can format stringable classes an error')
202
 
 
203
206
    def test_report_broken_pipe(self):
204
207
        try:
205
208
            raise IOError(errno.EPIPE, 'broken pipe foofofo')
206
 
        except IOError:
 
209
        except IOError as e:
207
210
            msg = _format_exception()
208
211
            self.assertEqual(msg, "brz: broken pipe\n")
209
212
        else:
210
213
            self.fail("expected error not raised")
211
214
 
212
 
    def assertLogContainsLine(self, log, string):
213
 
        """Assert log contains a line including log timestamp."""
214
 
        # Does not check absolute position in log as there may be kipple.
 
215
    def assertLogStartsWith(self, log, string):
 
216
        """Like assertStartsWith, but skips the log timestamp."""
215
217
        self.assertContainsRe(log,
216
 
                              '(?m)^\\d+\\.\\d+  ' + re.escape(string))
 
218
            '^\\d+\\.\\d+  ' + re.escape(string))
217
219
 
218
220
    def test_mutter_callsite_1(self):
219
221
        """mutter_callsite can capture 1 level of stack frame."""
220
222
        mutter_callsite(1, "foo %s", "a string")
221
223
        log = self.get_log()
222
224
        # begin with the message
223
 
        self.assertLogContainsLine(log, 'foo a string\nCalled from:\n')
 
225
        self.assertLogStartsWith(log, 'foo a string\nCalled from:\n')
224
226
        # 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')
 
227
        self.assertContainsRe(log,
 
228
            'test_trace\\.py", line \\d+, in test_mutter_callsite_1\n')
227
229
        # this frame should be the final one
228
230
        self.assertEndsWith(log, ' "a string")\n')
229
231
 
232
234
        mutter_callsite(2, "foo %s", "a string")
233
235
        log = self.get_log()
234
236
        # begin with the message
235
 
        self.assertLogContainsLine(log, 'foo a string\nCalled from:\n')
 
237
        self.assertLogStartsWith(log, 'foo a string\nCalled from:\n')
236
238
        # 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')
 
239
        self.assertContainsRe(log,
 
240
            'test_trace.py", line \d+, in test_mutter_callsite_2\n')
239
241
        # this frame should be the final one
240
242
        self.assertEndsWith(log, ' "a string")\n')
241
243
 
242
244
    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
 
245
        # Even if the decode/encode stage fails, mutter should not
 
246
        # raise an exception
 
247
        # This test checks that mutter doesn't fail; the current behaviour
 
248
        # is that it doesn't fail *and writes non-utf8*.
 
249
        mutter(u'Writing a greek mu (\xb5) works in a unicode string')
 
250
        mutter('But fails in an ascii string \xb5')
 
251
        mutter('and in an ascii argument: %s', '\xb5')
250
252
        log = self.get_log()
251
 
        self.assertContainsRe(
252
 
            log,
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')
 
253
        self.assertContainsRe(log, 'Writing a greek mu')
 
254
        self.assertContainsRe(log, "But fails in an ascii string")
 
255
        # However, the log content object does unicode replacement on reading
 
256
        # to let it get unicode back where good data has been written. So we
 
257
        # have to do a replaceent here as well.
 
258
        self.assertContainsRe(log, "ascii argument: \xb5".decode('utf8',
 
259
            'replace'))
258
260
 
259
261
    def test_show_error(self):
260
262
        show_error('error1')
261
263
        show_error(u'error2 \xb5 blah')
262
264
        show_error('arg: %s', 'blah')
263
 
        show_error('arg2: %(key)s', {'key': 'stuff'})
 
265
        show_error('arg2: %(key)s', {'key':'stuff'})
264
266
        try:
265
267
            raise Exception("oops")
266
 
        except BaseException:
 
268
        except:
267
269
            show_error('kwarg', exc_info=True)
268
270
        log = self.get_log()
269
271
        self.assertContainsRe(log, 'error1')
272
274
        self.assertContainsRe(log, 'arg2: stuff')
273
275
        self.assertContainsRe(log, 'kwarg')
274
276
        self.assertContainsRe(log, 'Traceback \\(most recent call last\\):')
275
 
        self.assertContainsRe(
276
 
            log, 'File ".*test_trace.py", line .*, in test_show_error')
 
277
        self.assertContainsRe(log, 'File ".*test_trace.py", line .*, in test_show_error')
277
278
        self.assertContainsRe(log, 'raise Exception\\("oops"\\)')
278
279
        self.assertContainsRe(log, 'Exception: oops')
279
280
 
302
303
            # as there's a timestamp at the front.
303
304
            tmp1.seek(0)
304
305
            self.assertContainsRe(tmp1.read(),
305
 
                                  b"\\d+\\.\\d+  comment to file1\n"
306
 
                                  b"\\d+\\.\\d+  again to file1\n")
 
306
                r"\d+\.\d+  comment to file1\n\d+\.\d+  again to file1\n")
307
307
            tmp2.seek(0)
308
308
            self.assertContainsRe(tmp2.read(),
309
 
                                  b"\\d+\\.\\d+  comment to file2\n")
 
309
                r"\d+\.\d+  comment to file2\n")
310
310
        finally:
311
311
            tmp1.close()
312
312
            tmp2.close()
315
315
        # If _open_brz_log cannot open the file, then we should write the
316
316
        # warning to stderr. Since this is normally happening before logging is
317
317
        # set up.
318
 
        self.overrideAttr(sys, 'stderr', StringIO())
 
318
        self.overrideAttr(sys, 'stderr', BytesIO())
319
319
        # Set the log file to something that cannot exist
320
320
        self.overrideEnv('BRZ_LOG', '/no-such-dir/brz.log')
321
321
        self.overrideAttr(trace, '_brz_log_filename')
322
322
        logf = trace._open_brz_log()
323
 
        if os.path.isdir('/no-such-dir'):
324
 
            raise TestSkipped('directory creation succeeded')
325
323
        self.assertIs(None, logf)
326
324
        self.assertContainsRe(
327
325
            sys.stderr.getvalue(),
328
326
            "failed to open trace file: .* '/no-such-dir/brz.log'$")
329
327
 
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'$")
347
 
 
348
328
 
349
329
class TestVerbosityLevel(TestCase):
350
330
 
398
378
        self.assertEqual(u"   DEBUG  \xa7\n", self.get_log())
399
379
 
400
380
    def test_log_utf8_msg(self):
401
 
        logging.getLogger("brz").debug(b"\xc2\xa7")
 
381
        logging.getLogger("brz").debug("\xc2\xa7")
402
382
        self.assertEqual(u"   DEBUG  \xa7\n", self.get_log())
403
383
 
404
384
    def test_log_utf8_arg(self):
405
 
        logging.getLogger("brz").debug(b"%s", b"\xc2\xa7")
406
 
        expected = u"   DEBUG  b'\\xc2\\xa7'\n"
407
 
        self.assertEqual(expected, self.get_log())
 
385
        logging.getLogger("brz").debug("%s", "\xc2\xa7")
 
386
        self.assertEqual(u"   DEBUG  \xa7\n", self.get_log())
408
387
 
409
388
    def test_log_bytes_msg(self):
410
 
        logging.getLogger("brz").debug(b"\xa7")
 
389
        logging.getLogger("brz").debug("\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.assertContainsString(log,
 
393
            "Logging record unformattable: '\\xa7' % ()\n")
415
394
 
416
395
    def test_log_bytes_arg(self):
417
 
        logging.getLogger("brz").debug(b"%s", b"\xa7")
 
396
        logging.getLogger("brz").debug("%s", "\xa7")
418
397
        log = self.get_log()
419
 
        self.assertEqual(u"   DEBUG  b'\\xa7'\n", self.get_log())
 
398
        self.assertContainsString(log, "UnicodeDecodeError: ")
 
399
        self.assertContainsString(log,
 
400
            "Logging record unformattable: '%s' % ('\\xa7',)\n")
420
401
 
421
402
    def test_log_mixed_strings(self):
422
 
        logging.getLogger("brz").debug(u"%s", b"\xa7")
 
403
        logging.getLogger("brz").debug(u"%s", "\xa7")
423
404
        log = self.get_log()
424
 
        self.assertEqual(u"   DEBUG  b'\\xa7'\n", self.get_log())
 
405
        self.assertContainsString(log, "UnicodeDecodeError: ")
 
406
        self.assertContainsString(log,
 
407
            "Logging record unformattable: u'%s' % ('\\xa7',)\n")
425
408
 
426
409
    def test_log_repr_broken(self):
427
410
        class BadRepr(object):