/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: Breezy landing bot
  • Author(s): Colin Watson
  • Date: 2020-11-16 21:47:08 UTC
  • mfrom: (7521.1.1 remove-lp-workaround)
  • Revision ID: breezy.the.bot@gmail.com-20201116214708-jos209mgxi41oy15
Remove breezy.git workaround for bazaar.launchpad.net.

Merged from https://code.launchpad.net/~cjwatson/brz/remove-lp-workaround/+merge/393710

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005-2011, 2016 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
18
18
 
19
19
"""Tests for trace library"""
20
20
 
21
 
from cStringIO import StringIO
22
21
import errno
 
22
from io import StringIO
23
23
import logging
24
24
import os
25
25
import re
26
26
import sys
27
27
import tempfile
28
28
 
29
 
from bzrlib import (
 
29
from .. import (
30
30
    debug,
31
31
    errors,
32
32
    trace,
33
33
    )
34
 
from bzrlib.tests import features, TestCaseInTempDir, TestCase
35
 
from bzrlib.trace import (
 
34
from . import features, TestCaseInTempDir, TestCase, TestSkipped
 
35
from ..trace import (
36
36
    mutter, mutter_callsite, report_exception,
37
37
    set_verbosity_level, get_verbosity_level, is_quiet, is_verbose, be_quiet,
38
38
    pop_log_file,
53
53
 
54
54
    def test_format_sys_exception(self):
55
55
        # Test handling of an internal/unexpected error that probably
56
 
        # indicates a bug in bzr.  The details of the message may vary
 
56
        # indicates a bug in brz.  The details of the message may vary
57
57
        # depending on whether apport is available or not.  See test_crash for
58
58
        # more.
59
59
        try:
60
 
            raise NotImplementedError, "time travel"
 
60
            raise NotImplementedError("time travel")
61
61
        except NotImplementedError:
62
 
            pass
63
 
        err = _format_exception()
64
 
        self.assertEqualDiff(err.splitlines()[0],
65
 
                'bzr: ERROR: exceptions.NotImplementedError: time travel')
66
 
        self.assertContainsRe(err,
67
 
            'Bazaar has encountered an internal error.')
 
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.')
68
67
 
69
68
    def test_format_interrupt_exception(self):
70
69
        try:
71
70
            raise KeyboardInterrupt()
72
71
        except KeyboardInterrupt:
73
72
            # XXX: Some risk that a *real* keyboard interrupt won't be seen
74
 
            pass
75
 
        msg = _format_exception()
76
 
        self.assertTrue(len(msg) > 0)
77
 
        self.assertEqualDiff(msg, 'bzr: interrupted\n')
 
73
            msg = _format_exception()
 
74
        self.assertEqual(msg, 'brz: interrupted\n')
78
75
 
79
76
    def test_format_memory_error(self):
80
77
        try:
81
78
            raise MemoryError()
82
79
        except MemoryError:
83
 
            pass
84
 
        msg = _format_exception()
85
 
        self.assertEquals(msg,
86
 
            "bzr: out of memory\nUse -Dmem_dump to dump memory to a file.\n")
 
80
            msg = _format_exception()
 
81
        self.assertEqual(
 
82
            msg,
 
83
            "brz: out of memory\nUse -Dmem_dump to dump memory to a file.\n")
87
84
 
88
85
    def test_format_mem_dump(self):
89
86
        self.requireFeature(features.meliae)
91
88
        try:
92
89
            raise MemoryError()
93
90
        except MemoryError:
94
 
            pass
95
 
        msg = _format_exception()
 
91
            msg = _format_exception()
96
92
        self.assertStartsWith(msg,
97
 
            "bzr: out of memory\nMemory dumped to ")
 
93
                              "brz: out of memory\nMemory dumped to ")
98
94
 
99
95
    def test_format_os_error(self):
100
96
        try:
101
97
            os.rmdir('nosuchfile22222')
102
 
        except OSError, e:
 
98
        except OSError as e:
103
99
            e_str = str(e)
104
 
        msg = _format_exception()
 
100
            msg = _format_exception()
105
101
        # Linux seems to give "No such file" but Windows gives "The system
106
102
        # cannot find the file specified".
107
 
        self.assertEqual('bzr: ERROR: %s\n' % (e_str,), msg)
 
103
        self.assertEqual('brz: ERROR: %s\n' % (e_str,), msg)
108
104
 
109
105
    def test_format_io_error(self):
110
106
        try:
111
 
            file('nosuchfile22222')
 
107
            open('nosuchfile22222')
112
108
        except IOError:
113
 
            pass
114
 
        msg = _format_exception()
 
109
            msg = _format_exception()
115
110
        # Even though Windows and Linux differ for 'os.rmdir', they both give
116
111
        # 'No such file' for open()
117
 
        # However it now gets translated so we can not test for a specific message
 
112
        # However it now gets translated so we can not test for a specific
 
113
        # message
118
114
        self.assertContainsRe(msg,
119
 
            r'^bzr: ERROR: \[Errno .*\] .*nosuchfile')
 
115
                              '^brz: ERROR: \\[Errno .*\\] .*nosuchfile')
120
116
 
121
117
    def test_format_pywintypes_error(self):
122
118
        self.requireFeature(features.pywintypes)
123
 
        import pywintypes, win32file
 
119
        import pywintypes
 
120
        import win32file
124
121
        try:
125
122
            win32file.RemoveDirectory('nosuchfile22222')
126
123
        except pywintypes.error:
127
 
            pass
128
 
        msg = _format_exception()
 
124
            msg = _format_exception()
129
125
        # GZ 2010-05-03: Formatting for pywintypes.error is basic, a 3-tuple
130
126
        #                with errno, function name, and locale error message
131
 
        self.assertContainsRe(msg,
132
 
            r"^bzr: ERROR: \(2, 'RemoveDirectory[AW]?', .*\)")
133
 
            
 
127
        self.assertContainsRe(
 
128
            msg, "^brz: ERROR: \\(2, 'RemoveDirectory[AW]?', .*\\)")
 
129
 
134
130
    def test_format_sockets_error(self):
135
131
        try:
136
132
            import socket
137
133
            sock = socket.socket()
138
 
            sock.send("This should fail.")
 
134
            sock.send(b"This should fail.")
139
135
        except socket.error:
140
 
            pass
141
 
        msg = _format_exception()
142
 
        
 
136
            msg = _format_exception()
 
137
 
143
138
        self.assertNotContainsRe(msg,
144
 
            r"Traceback (most recent call last):")
 
139
                                 "Traceback \\(most recent call last\\):")
145
140
 
146
141
    def test_format_unicode_error(self):
147
142
        try:
148
 
            raise errors.BzrCommandError(u'argument foo\xb5 does not exist')
149
 
        except errors.BzrCommandError:
150
 
            pass
151
 
        msg = _format_exception()
 
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)
152
148
 
153
149
    def test_format_exception(self):
154
 
        """Short formatting of bzr exceptions"""
 
150
        """Short formatting of brz exceptions"""
155
151
        try:
156
152
            raise errors.NotBranchError('wibble')
157
153
        except errors.NotBranchError:
158
 
            pass
159
 
        msg = _format_exception()
160
 
        self.assertTrue(len(msg) > 0)
161
 
        self.assertEqualDiff(msg, 'bzr: ERROR: Not a branch: \"wibble\".\n')
 
154
            msg = _format_exception()
 
155
        self.assertEqual(msg, 'brz: ERROR: Not a branch: \"wibble\".\n')
162
156
 
163
157
    def test_report_external_import_error(self):
164
158
        """Short friendly message for missing system modules."""
165
159
        try:
166
160
            import ImaginaryModule
167
 
        except ImportError, e:
168
 
            pass
 
161
        except ImportError:
 
162
            msg = _format_exception()
169
163
        else:
170
164
            self.fail("somehow succeeded in importing %r" % ImaginaryModule)
171
 
        msg = _format_exception()
172
 
        self.assertEqual(msg,
173
 
            'bzr: ERROR: No module named ImaginaryModule\n'
174
 
            'You may need to install this Python library separately.\n')
 
165
        self.assertContainsRe(
 
166
            msg,
 
167
            "^brz: ERROR: No module named '?ImaginaryModule'?\n"
 
168
            "You may need to install this Python library separately.\n$")
175
169
 
176
170
    def test_report_import_syntax_error(self):
177
171
        try:
178
172
            raise ImportError("syntax error")
179
 
        except ImportError, e:
180
 
            pass
181
 
        msg = _format_exception()
 
173
        except ImportError:
 
174
            msg = _format_exception()
182
175
        self.assertContainsRe(msg,
183
 
            r'Bazaar has encountered an internal error')
 
176
                              'Bazaar has encountered an internal error')
184
177
 
185
178
    def test_trace_unicode(self):
186
179
        """Write Unicode to trace log"""
201
194
        log = self.get_log()
202
195
        self.assertContainsRe(log, 'the unicode character')
203
196
 
 
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
 
204
203
    def test_report_broken_pipe(self):
205
204
        try:
206
205
            raise IOError(errno.EPIPE, 'broken pipe foofofo')
207
 
        except IOError, e:
 
206
        except IOError:
208
207
            msg = _format_exception()
209
 
            self.assertEquals(msg, "bzr: broken pipe\n")
 
208
            self.assertEqual(msg, "brz: broken pipe\n")
210
209
        else:
211
210
            self.fail("expected error not raised")
212
211
 
213
 
    def assertLogStartsWith(self, log, string):
214
 
        """Like assertStartsWith, but skips the log timestamp."""
 
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
215
        self.assertContainsRe(log,
216
 
            '^\\d+\\.\\d+  ' + re.escape(string))
 
216
                              '(?m)^\\d+\\.\\d+  ' + re.escape(string))
217
217
 
218
218
    def test_mutter_callsite_1(self):
219
219
        """mutter_callsite can capture 1 level of stack frame."""
220
220
        mutter_callsite(1, "foo %s", "a string")
221
221
        log = self.get_log()
222
222
        # begin with the message
223
 
        self.assertLogStartsWith(log, 'foo a string\nCalled from:\n')
 
223
        self.assertLogContainsLine(log, 'foo a string\nCalled from:\n')
224
224
        # should show two frame: this frame and the one above
225
 
        self.assertContainsRe(log,
226
 
            'test_trace\\.py", line \\d+, in test_mutter_callsite_1\n')
 
225
        self.assertContainsRe(
 
226
            log, 'test_trace\\.py", line \\d+, in test_mutter_callsite_1\n')
227
227
        # this frame should be the final one
228
228
        self.assertEndsWith(log, ' "a string")\n')
229
229
 
232
232
        mutter_callsite(2, "foo %s", "a string")
233
233
        log = self.get_log()
234
234
        # begin with the message
235
 
        self.assertLogStartsWith(log, 'foo a string\nCalled from:\n')
 
235
        self.assertLogContainsLine(log, 'foo a string\nCalled from:\n')
236
236
        # should show two frame: this frame and the one above
237
 
        self.assertContainsRe(log,
238
 
            'test_trace.py", line \d+, in test_mutter_callsite_2\n')
 
237
        self.assertContainsRe(
 
238
            log, 'test_trace.py", line \\d+, in test_mutter_callsite_2\n')
239
239
        # this frame should be the final one
240
240
        self.assertEndsWith(log, ' "a string")\n')
241
241
 
242
242
    def test_mutter_never_fails(self):
243
 
        # Even if the decode/encode stage fails, mutter should not
244
 
        # raise an exception
245
 
        # This test checks that mutter doesn't fail; the current behaviour
246
 
        # is that it doesn't fail *and writes non-utf8*.
247
 
        mutter(u'Writing a greek mu (\xb5) works in a unicode string')
248
 
        mutter('But fails in an ascii string \xb5')
249
 
        mutter('and in an ascii argument: %s', '\xb5')
 
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
250
250
        log = self.get_log()
251
 
        self.assertContainsRe(log, 'Writing a greek mu')
252
 
        self.assertContainsRe(log, "But fails in an ascii string")
253
 
        # However, the log content object does unicode replacement on reading
254
 
        # to let it get unicode back where good data has been written. So we
255
 
        # have to do a replaceent here as well.
256
 
        self.assertContainsRe(log, "ascii argument: \xb5".decode('utf8',
257
 
            'replace'))
 
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')
258
258
 
259
259
    def test_show_error(self):
260
260
        show_error('error1')
261
261
        show_error(u'error2 \xb5 blah')
262
262
        show_error('arg: %s', 'blah')
263
 
        show_error('arg2: %(key)s', {'key':'stuff'})
 
263
        show_error('arg2: %(key)s', {'key': 'stuff'})
264
264
        try:
265
265
            raise Exception("oops")
266
 
        except:
 
266
        except BaseException:
267
267
            show_error('kwarg', exc_info=True)
268
268
        log = self.get_log()
269
269
        self.assertContainsRe(log, 'error1')
272
272
        self.assertContainsRe(log, 'arg2: stuff')
273
273
        self.assertContainsRe(log, 'kwarg')
274
274
        self.assertContainsRe(log, 'Traceback \\(most recent call last\\):')
275
 
        self.assertContainsRe(log, 'File ".*test_trace.py", line .*, in test_show_error')
 
275
        self.assertContainsRe(
 
276
            log, 'File ".*test_trace.py", line .*, in test_show_error')
276
277
        self.assertContainsRe(log, 'raise Exception\\("oops"\\)')
277
278
        self.assertContainsRe(log, 'Exception: oops')
278
279
 
301
302
            # as there's a timestamp at the front.
302
303
            tmp1.seek(0)
303
304
            self.assertContainsRe(tmp1.read(),
304
 
                r"\d+\.\d+  comment to file1\n\d+\.\d+  again to file1\n")
 
305
                                  b"\\d+\\.\\d+  comment to file1\n"
 
306
                                  b"\\d+\\.\\d+  again to file1\n")
305
307
            tmp2.seek(0)
306
308
            self.assertContainsRe(tmp2.read(),
307
 
                r"\d+\.\d+  comment to file2\n")
 
309
                                  b"\\d+\\.\\d+  comment to file2\n")
308
310
        finally:
309
311
            tmp1.close()
310
312
            tmp2.close()
311
313
 
312
 
    def test__open_bzr_log_uses_stderr_for_failures(self):
313
 
        # If _open_bzr_log cannot open the file, then we should write the
 
314
    def test__open_brz_log_uses_stderr_for_failures(self):
 
315
        # If _open_brz_log cannot open the file, then we should write the
314
316
        # warning to stderr. Since this is normally happening before logging is
315
317
        # set up.
316
318
        self.overrideAttr(sys, 'stderr', StringIO())
317
319
        # Set the log file to something that cannot exist
318
 
        self.overrideEnv('BZR_LOG', os.getcwd() + '/no-dir/bzr.log')
319
 
        self.overrideAttr(trace, '_bzr_log_filename')
320
 
        logf = trace._open_bzr_log()
321
 
        self.assertIs(None, logf)
322
 
        self.assertContainsRe(sys.stderr.getvalue(),
323
 
                              'failed to open trace file: .*/no-dir/bzr.log')
 
320
        self.overrideEnv('BRZ_LOG', '/no-such-dir/brz.log')
 
321
        self.overrideAttr(trace, '_brz_log_filename')
 
322
        logf = trace._open_brz_log()
 
323
        if os.path.isdir('/no-such-dir'):
 
324
            raise TestSkipped('directory creation succeeded')
 
325
        self.assertIs(None, logf)
 
326
        self.assertContainsRe(
 
327
            sys.stderr.getvalue(),
 
328
            "failed to open trace file: .* '/no-such-dir/brz.log'$")
 
329
 
 
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'$")
324
347
 
325
348
 
326
349
class TestVerbosityLevel(TestCase):
359
382
        self.assertEqual(" WARNING  Warned\n", self.get_log())
360
383
 
361
384
    def test_log(self):
362
 
        logging.getLogger("bzr").error("Errored")
 
385
        logging.getLogger("brz").error("Errored")
363
386
        self.assertEqual("   ERROR  Errored\n", self.get_log())
364
387
 
365
388
    def test_log_sub(self):
366
 
        logging.getLogger("bzr.test_log_sub").debug("Whispered")
 
389
        logging.getLogger("brz.test_log_sub").debug("Whispered")
367
390
        self.assertEqual("   DEBUG  Whispered\n", self.get_log())
368
391
 
369
392
    def test_log_unicode_msg(self):
370
 
        logging.getLogger("bzr").debug(u"\xa7")
 
393
        logging.getLogger("brz").debug(u"\xa7")
371
394
        self.assertEqual(u"   DEBUG  \xa7\n", self.get_log())
372
395
 
373
396
    def test_log_unicode_arg(self):
374
 
        logging.getLogger("bzr").debug("%s", u"\xa7")
 
397
        logging.getLogger("brz").debug("%s", u"\xa7")
375
398
        self.assertEqual(u"   DEBUG  \xa7\n", self.get_log())
376
399
 
377
400
    def test_log_utf8_msg(self):
378
 
        logging.getLogger("bzr").debug("\xc2\xa7")
 
401
        logging.getLogger("brz").debug(b"\xc2\xa7")
379
402
        self.assertEqual(u"   DEBUG  \xa7\n", self.get_log())
380
403
 
381
404
    def test_log_utf8_arg(self):
382
 
        logging.getLogger("bzr").debug("%s", "\xc2\xa7")
383
 
        self.assertEqual(u"   DEBUG  \xa7\n", self.get_log())
 
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())
384
408
 
385
409
    def test_log_bytes_msg(self):
386
 
        logging.getLogger("bzr").debug("\xa7")
 
410
        logging.getLogger("brz").debug(b"\xa7")
387
411
        log = self.get_log()
388
412
        self.assertContainsString(log, "UnicodeDecodeError: ")
389
 
        self.assertContainsString(log,
390
 
            "Logging record unformattable: '\\xa7' % ()\n")
 
413
        self.assertContainsRe(
 
414
            log, "Logging record unformattable: b?'\\\\xa7' % \\(\\)\n")
391
415
 
392
416
    def test_log_bytes_arg(self):
393
 
        logging.getLogger("bzr").debug("%s", "\xa7")
 
417
        logging.getLogger("brz").debug(b"%s", b"\xa7")
394
418
        log = self.get_log()
395
 
        self.assertContainsString(log, "UnicodeDecodeError: ")
396
 
        self.assertContainsString(log,
397
 
            "Logging record unformattable: '%s' % ('\\xa7',)\n")
 
419
        self.assertEqual(u"   DEBUG  b'\\xa7'\n", self.get_log())
398
420
 
399
421
    def test_log_mixed_strings(self):
400
 
        logging.getLogger("bzr").debug(u"%s", "\xa7")
 
422
        logging.getLogger("brz").debug(u"%s", b"\xa7")
401
423
        log = self.get_log()
402
 
        self.assertContainsString(log, "UnicodeDecodeError: ")
403
 
        self.assertContainsString(log,
404
 
            "Logging record unformattable: u'%s' % ('\\xa7',)\n")
 
424
        self.assertEqual(u"   DEBUG  b'\\xa7'\n", self.get_log())
405
425
 
406
426
    def test_log_repr_broken(self):
407
427
        class BadRepr(object):
408
428
            def __repr__(self):
409
429
                raise ValueError("Broken object")
410
 
        logging.getLogger("bzr").debug("%s", BadRepr())
 
430
        logging.getLogger("brz").debug("%s", BadRepr())
411
431
        log = self.get_log()
412
432
        self.assertContainsRe(log, "ValueError: Broken object\n")
413
433
        self.assertContainsRe(log, "Logging record unformattable: '%s' % .*\n")
429
449
 
430
450
    def test_default_config(self):
431
451
        config = trace.DefaultConfig()
432
 
        self.overrideAttr(trace, "_bzr_log_filename", None)
433
 
        trace._bzr_log_filename = None
434
 
        expected_filename = trace._get_bzr_log_filename()
435
 
        self.assertEqual(None, trace._bzr_log_filename)
 
452
        self.overrideAttr(trace, "_brz_log_filename", None)
 
453
        trace._brz_log_filename = None
 
454
        expected_filename = trace._get_brz_log_filename()
 
455
        self.assertEqual(None, trace._brz_log_filename)
436
456
        config.__enter__()
437
457
        try:
438
458
            # Should have entered and setup a default filename.
439
 
            self.assertEqual(expected_filename, trace._bzr_log_filename)
 
459
            self.assertEqual(expected_filename, trace._brz_log_filename)
440
460
        finally:
441
461
            config.__exit__(None, None, None)
442
462
            # Should have exited and cleaned up.
443
 
            self.assertEqual(None, trace._bzr_log_filename)
 
463
            self.assertEqual(None, trace._brz_log_filename)