160
159
Error and debug log messages are redirected from their usual
161
160
location into a temporary file, the contents of which can be
162
retrieved by _get_log().
161
retrieved by _get_log(). We use a real OS file, not an in-memory object,
162
so that it can also capture file IO. When the test completes this file
163
is read into memory and removed from disk.
164
165
There are also convenience functions to invoke bzr's command-line
165
routine, and to build and check bzr trees."""
166
routine, and to build and check bzr trees.
168
In addition to the usual method of overriding tearDown(), this class also
169
allows subclasses to register functions into the _cleanups list, which is
170
run in order as the object is torn down. It's less likely this will be
171
accidentally overlooked.
168
175
_log_file_name = None
171
179
unittest.TestCase.setUp(self)
172
self.oldenv = os.environ.get('HOME', None)
173
os.environ['HOME'] = os.getcwd()
174
self.bzr_email = os.environ.get('BZREMAIL')
175
if self.bzr_email is not None:
176
del os.environ['BZREMAIL']
177
self.email = os.environ.get('EMAIL')
178
if self.email is not None:
179
del os.environ['EMAIL']
181
self._cleanEnvironment()
180
182
bzrlib.trace.disable_default_logging()
181
self._enable_file_logging()
183
185
def _ndiff_strings(self, a, b):
184
186
"""Return ndiff between two strings containing lines.
212
214
if not re.search(needle_re, haystack):
213
215
raise AssertionError('pattern "%s" not found in "%s"'
214
216
% (needle_re, haystack))
216
def _enable_file_logging(self):
218
def _startLogFile(self):
219
"""Send bzr and test log messages to a temporary file.
221
The file is removed as the test is torn down.
217
223
fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
219
224
self._log_file = os.fdopen(fileno, 'w+')
221
225
hdlr = logging.StreamHandler(self._log_file)
222
226
hdlr.setLevel(logging.DEBUG)
223
227
hdlr.setFormatter(logging.Formatter('%(levelname)8s %(message)s'))
225
229
logging.getLogger('').setLevel(logging.DEBUG)
226
230
self._log_hdlr = hdlr
227
231
debug('opened log file %s', name)
229
232
self._log_file_name = name
233
self.addCleanup(self._finishLogFile)
235
def _finishLogFile(self):
236
"""Finished with the log file.
238
Read contents into memory, close, and delete.
240
self._log_file.seek(0)
241
self._log_contents = self._log_file.read()
242
os.remove(self._log_file_name)
243
self._log_file = self._log_file_name = None
245
def addCleanup(self, callable):
246
"""Arrange to run a callable when this case is torn down.
248
Callables are run in the reverse of the order they are registered,
249
ie last-in first-out.
251
if callable in self._cleanups:
252
raise ValueError("cleanup function %r already registered on %s"
254
self._cleanups.append(callable)
256
def _cleanEnvironment(self):
257
self.oldenv = os.environ.get('HOME', None)
258
os.environ['HOME'] = os.getcwd()
259
self.bzr_email = os.environ.get('BZREMAIL')
260
if self.bzr_email is not None:
261
del os.environ['BZREMAIL']
262
self.email = os.environ.get('EMAIL')
263
if self.email is not None:
264
del os.environ['EMAIL']
265
self.addCleanup(self._restoreEnvironment)
267
def _restoreEnvironment(self):
232
268
os.environ['HOME'] = self.oldenv
233
269
if os.environ.get('BZREMAIL') is not None:
234
270
del os.environ['BZREMAIL']
238
274
del os.environ['EMAIL']
239
275
if self.email is not None:
240
276
os.environ['EMAIL'] = self.email
241
279
logging.getLogger('').removeHandler(self._log_hdlr)
242
280
bzrlib.trace.enable_default_logging()
243
281
logging.debug('%s teardown', self.id())
244
self._log_file.close()
245
283
unittest.TestCase.tearDown(self)
285
def _runCleanups(self):
286
"""Run registered cleanup functions.
288
This should only be called from TestCase.tearDown.
290
for callable in reversed(self._cleanups):
247
293
def log(self, *args):
248
294
logging.debug(*args)
418
464
os.mkdir(os.path.join(TestCaseInTempDir.TEST_ROOT, '.bzr'))
467
super(TestCaseInTempDir, self).setUp()
421
468
self._make_test_root()
422
self._currentdir = os.getcwdu()
469
_currentdir = os.getcwdu()
423
470
short_id = self.id().replace('bzrlib.selftest.', '') \
424
471
.replace('__main__.', '')
425
472
self.test_dir = os.path.join(self.TEST_ROOT, short_id)
426
473
os.mkdir(self.test_dir)
427
474
os.chdir(self.test_dir)
428
super(TestCaseInTempDir, self).setUp()
475
def _leaveDirectory():
476
os.chdir(_currentdir)
477
self.addCleanup(_leaveDirectory)
431
os.chdir(self._currentdir)
432
super(TestCaseInTempDir, self).tearDown()
434
479
def build_tree(self, shape):
435
480
"""Build a test tree according to a pattern.
456
501
"""Fail unless path, which may be abs or relative, exists."""
457
502
self.failUnless(osutils.lexists(path))
504
def assertFileEqual(self, content, path):
505
"""Fail if path does not contain 'content'."""
506
self.failUnless(osutils.lexists(path))
507
self.assertEqualDiff(content, open(path, 'r').read())
460
510
class MetaTestLog(TestCase):
461
511
def test_logging(self):
521
571
'bzrlib.selftest.testinv',
522
572
'bzrlib.selftest.test_ancestry',
523
573
'bzrlib.selftest.test_commit',
574
'bzrlib.selftest.test_command',
524
575
'bzrlib.selftest.test_commit_merge',
525
576
'bzrlib.selftest.testconfig',
526
577
'bzrlib.selftest.versioning',
557
608
'bzrlib.selftest.testoptions',
558
609
'bzrlib.selftest.testhttp',
559
610
'bzrlib.selftest.testnonascii',
611
'bzrlib.selftest.testreweave',
612
'bzrlib.selftest.testtsort',
562
615
for m in (bzrlib.store, bzrlib.inventory, bzrlib.branch,