/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: Martin
  • Date: 2018-06-30 23:39:17 UTC
  • mto: This revision was merged to the branch mainline in revision 7013.
  • Revision ID: gzlist@googlemail.com-20180630233917-4lh8na2wist64hab
Make replacement for lazy import tests less dodgy

Should fix tests that fail under CI but seem to pass locally by not
doing an unsafe replacement of the __import__ builtin. Instead alias
it at the module level for replacement in testing.

Show diffs side-by-side

added added

removed removed

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