~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_trace.py

(jelmer) Use the absolute_import feature everywhere in bzrlib,
 and add a source test to make sure it's used everywhere. (Jelmer Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
 
1
# Copyright (C) 2005-2011 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
20
20
 
21
21
from cStringIO import StringIO
22
22
import errno
 
23
import logging
23
24
import os
24
25
import re
25
26
import sys
26
27
import tempfile
27
28
 
28
29
from bzrlib import (
 
30
    debug,
29
31
    errors,
 
32
    trace,
30
33
    )
31
 
from bzrlib.tests import TestCaseInTempDir, TestCase
 
34
from bzrlib.tests import features, TestCaseInTempDir, TestCase
32
35
from bzrlib.trace import (
33
36
    mutter, mutter_callsite, report_exception,
34
37
    set_verbosity_level, get_verbosity_level, is_quiet, is_verbose, be_quiet,
35
38
    pop_log_file,
36
39
    push_log_file,
37
40
    _rollover_trace_maybe,
 
41
    show_error,
38
42
    )
39
43
 
40
44
 
79
83
            pass
80
84
        msg = _format_exception()
81
85
        self.assertEquals(msg,
82
 
            "bzr: out of memory\n")
 
86
            "bzr: out of memory\nUse -Dmem_dump to dump memory to a file.\n")
 
87
 
 
88
    def test_format_mem_dump(self):
 
89
        self.requireFeature(features.meliae)
 
90
        debug.debug_flags.add('mem_dump')
 
91
        try:
 
92
            raise MemoryError()
 
93
        except MemoryError:
 
94
            pass
 
95
        msg = _format_exception()
 
96
        self.assertStartsWith(msg,
 
97
            "bzr: out of memory\nMemory dumped to ")
83
98
 
84
99
    def test_format_os_error(self):
85
100
        try:
99
114
        msg = _format_exception()
100
115
        # Even though Windows and Linux differ for 'os.rmdir', they both give
101
116
        # 'No such file' for open()
102
 
        self.assertContainsRe(msg,
103
 
            r'^bzr: ERROR: \[Errno .*\] No such file.*nosuchfile')
 
117
        # However it now gets translated so we can not test for a specific message
 
118
        self.assertContainsRe(msg,
 
119
            r'^bzr: ERROR: \[Errno .*\] .*nosuchfile')
 
120
 
 
121
    def test_format_pywintypes_error(self):
 
122
        self.requireFeature(features.pywintypes)
 
123
        import pywintypes, win32file
 
124
        try:
 
125
            win32file.RemoveDirectory('nosuchfile22222')
 
126
        except pywintypes.error:
 
127
            pass
 
128
        msg = _format_exception()
 
129
        # GZ 2010-05-03: Formatting for pywintypes.error is basic, a 3-tuple
 
130
        #                with errno, function name, and locale error message
 
131
        self.assertContainsRe(msg,
 
132
            r"^bzr: ERROR: \(2, 'RemoveDirectory[AW]?', .*\)")
 
133
            
 
134
    def test_format_sockets_error(self):
 
135
        try:
 
136
            import socket
 
137
            sock = socket.socket()
 
138
            sock.send("This should fail.")
 
139
        except socket.error:
 
140
            pass
 
141
        msg = _format_exception()
 
142
        
 
143
        self.assertNotContainsRe(msg,
 
144
            r"Traceback (most recent call last):")
104
145
 
105
146
    def test_format_unicode_error(self):
106
147
        try:
144
185
    def test_trace_unicode(self):
145
186
        """Write Unicode to trace log"""
146
187
        self.log(u'the unicode character for benzene is \N{BENZENE RING}')
147
 
        self.assertContainsRe(self._get_log(keep_log_file=True),
148
 
                              "the unicode character for benzene is")
 
188
        log = self.get_log()
 
189
        self.assertContainsRe(log, "the unicode character for benzene is")
149
190
 
150
191
    def test_trace_argument_unicode(self):
151
192
        """Write a Unicode argument to the trace log"""
152
193
        mutter(u'the unicode character for benzene is %s', u'\N{BENZENE RING}')
153
 
        self.assertContainsRe(self._get_log(keep_log_file=True),
154
 
                              'the unicode character')
 
194
        log = self.get_log()
 
195
        self.assertContainsRe(log, 'the unicode character')
155
196
 
156
197
    def test_trace_argument_utf8(self):
157
198
        """Write a Unicode argument to the trace log"""
158
199
        mutter(u'the unicode character for benzene is %s',
159
200
               u'\N{BENZENE RING}'.encode('utf-8'))
160
 
        self.assertContainsRe(self._get_log(keep_log_file=True),
161
 
                              'the unicode character')
 
201
        log = self.get_log()
 
202
        self.assertContainsRe(log, 'the unicode character')
162
203
 
163
204
    def test_report_broken_pipe(self):
164
205
        try:
177
218
    def test_mutter_callsite_1(self):
178
219
        """mutter_callsite can capture 1 level of stack frame."""
179
220
        mutter_callsite(1, "foo %s", "a string")
180
 
        log = self._get_log(keep_log_file=True)
 
221
        log = self.get_log()
181
222
        # begin with the message
182
223
        self.assertLogStartsWith(log, 'foo a string\nCalled from:\n')
183
224
        # should show two frame: this frame and the one above
189
230
    def test_mutter_callsite_2(self):
190
231
        """mutter_callsite can capture 2 levels of stack frame."""
191
232
        mutter_callsite(2, "foo %s", "a string")
192
 
        log = self._get_log(keep_log_file=True)
 
233
        log = self.get_log()
193
234
        # begin with the message
194
235
        self.assertLogStartsWith(log, 'foo a string\nCalled from:\n')
195
236
        # should show two frame: this frame and the one above
201
242
    def test_mutter_never_fails(self):
202
243
        # Even if the decode/encode stage fails, mutter should not
203
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*.
204
247
        mutter(u'Writing a greek mu (\xb5) works in a unicode string')
205
248
        mutter('But fails in an ascii string \xb5')
206
249
        mutter('and in an ascii argument: %s', '\xb5')
207
 
        log = self._get_log(keep_log_file=True)
 
250
        log = self.get_log()
208
251
        self.assertContainsRe(log, 'Writing a greek mu')
209
252
        self.assertContainsRe(log, "But fails in an ascii string")
210
 
        self.assertContainsRe(log, u"ascii argument: \xb5")
 
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'))
 
258
 
 
259
    def test_show_error(self):
 
260
        show_error('error1')
 
261
        show_error(u'error2 \xb5 blah')
 
262
        show_error('arg: %s', 'blah')
 
263
        show_error('arg2: %(key)s', {'key':'stuff'})
 
264
        try:
 
265
            raise Exception("oops")
 
266
        except:
 
267
            show_error('kwarg', exc_info=True)
 
268
        log = self.get_log()
 
269
        self.assertContainsRe(log, 'error1')
 
270
        self.assertContainsRe(log, u'error2 \xb5 blah')
 
271
        self.assertContainsRe(log, 'arg: blah')
 
272
        self.assertContainsRe(log, 'arg2: stuff')
 
273
        self.assertContainsRe(log, 'kwarg')
 
274
        self.assertContainsRe(log, 'Traceback \\(most recent call last\\):')
 
275
        self.assertContainsRe(log, 'File ".*test_trace.py", line .*, in test_show_error')
 
276
        self.assertContainsRe(log, 'raise Exception\\("oops"\\)')
 
277
        self.assertContainsRe(log, 'Exception: oops')
211
278
 
212
279
    def test_push_log_file(self):
213
280
        """Can push and pop log file, and this catches mutter messages.
242
309
            tmp1.close()
243
310
            tmp2.close()
244
311
 
 
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
        # warning to stderr. Since this is normally happening before logging is
 
315
        # set up.
 
316
        self.overrideAttr(sys, 'stderr', StringIO())
 
317
        # 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')
 
324
 
245
325
 
246
326
class TestVerbosityLevel(TestCase):
247
327
 
267
347
        self.assertEqual(0, get_verbosity_level())
268
348
 
269
349
 
 
350
class TestLogging(TestCase):
 
351
    """Check logging functionality robustly records information"""
 
352
 
 
353
    def test_note(self):
 
354
        trace.note("Noted")
 
355
        self.assertEqual("    INFO  Noted\n", self.get_log())
 
356
 
 
357
    def test_warning(self):
 
358
        trace.warning("Warned")
 
359
        self.assertEqual(" WARNING  Warned\n", self.get_log())
 
360
 
 
361
    def test_log(self):
 
362
        logging.getLogger("bzr").error("Errored")
 
363
        self.assertEqual("   ERROR  Errored\n", self.get_log())
 
364
 
 
365
    def test_log_sub(self):
 
366
        logging.getLogger("bzr.test_log_sub").debug("Whispered")
 
367
        self.assertEqual("   DEBUG  Whispered\n", self.get_log())
 
368
 
 
369
    def test_log_unicode_msg(self):
 
370
        logging.getLogger("bzr").debug(u"\xa7")
 
371
        self.assertEqual(u"   DEBUG  \xa7\n", self.get_log())
 
372
 
 
373
    def test_log_unicode_arg(self):
 
374
        logging.getLogger("bzr").debug("%s", u"\xa7")
 
375
        self.assertEqual(u"   DEBUG  \xa7\n", self.get_log())
 
376
 
 
377
    def test_log_utf8_msg(self):
 
378
        logging.getLogger("bzr").debug("\xc2\xa7")
 
379
        self.assertEqual(u"   DEBUG  \xa7\n", self.get_log())
 
380
 
 
381
    def test_log_utf8_arg(self):
 
382
        logging.getLogger("bzr").debug("%s", "\xc2\xa7")
 
383
        self.assertEqual(u"   DEBUG  \xa7\n", self.get_log())
 
384
 
 
385
    def test_log_bytes_msg(self):
 
386
        logging.getLogger("bzr").debug("\xa7")
 
387
        log = self.get_log()
 
388
        self.assertContainsString(log, "UnicodeDecodeError: ")
 
389
        self.assertContainsString(log,
 
390
            "Logging record unformattable: '\\xa7' % ()\n")
 
391
 
 
392
    def test_log_bytes_arg(self):
 
393
        logging.getLogger("bzr").debug("%s", "\xa7")
 
394
        log = self.get_log()
 
395
        self.assertContainsString(log, "UnicodeDecodeError: ")
 
396
        self.assertContainsString(log,
 
397
            "Logging record unformattable: '%s' % ('\\xa7',)\n")
 
398
 
 
399
    def test_log_mixed_strings(self):
 
400
        logging.getLogger("bzr").debug(u"%s", "\xa7")
 
401
        log = self.get_log()
 
402
        self.assertContainsString(log, "UnicodeDecodeError: ")
 
403
        self.assertContainsString(log,
 
404
            "Logging record unformattable: u'%s' % ('\\xa7',)\n")
 
405
 
 
406
    def test_log_repr_broken(self):
 
407
        class BadRepr(object):
 
408
            def __repr__(self):
 
409
                raise ValueError("Broken object")
 
410
        logging.getLogger("bzr").debug("%s", BadRepr())
 
411
        log = self.get_log()
 
412
        self.assertContainsRe(log, "ValueError: Broken object\n")
 
413
        self.assertContainsRe(log, "Logging record unformattable: '%s' % .*\n")
 
414
 
 
415
 
270
416
class TestBzrLog(TestCaseInTempDir):
271
417
 
272
418
    def test_log_rollover(self):
277
423
        _rollover_trace_maybe(temp_log_name)
278
424
        # should have been rolled over
279
425
        self.assertFalse(os.access(temp_log_name, os.R_OK))
 
426
 
 
427
 
 
428
class TestTraceConfiguration(TestCaseInTempDir):
 
429
 
 
430
    def test_default_config(self):
 
431
        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)
 
436
        config.__enter__()
 
437
        try:
 
438
            # Should have entered and setup a default filename.
 
439
            self.assertEqual(expected_filename, trace._bzr_log_filename)
 
440
        finally:
 
441
            config.__exit__(None, None, None)
 
442
            # Should have exited and cleaned up.
 
443
            self.assertEqual(None, trace._bzr_log_filename)