30
from logging import debug, warning, error
30
32
import bzrlib.commands
31
33
import bzrlib.trace
33
34
import bzrlib.osutils as osutils
34
35
from bzrlib.selftest import TestUtil
35
36
from bzrlib.selftest.TestUtil import TestLoader, TestSuite
36
37
from bzrlib.selftest.treeshape import build_tree_contents
38
from bzrlib.errors import BzrError
38
40
MODULES_TO_TEST = []
39
41
MODULES_TO_DOCTEST = []
41
from logging import debug, warning, error
45
45
class EarlyStoppingTestResultAdapter(object):
160
160
Error and debug log messages are redirected from their usual
161
161
location into a temporary file, the contents of which can be
162
retrieved by _get_log().
162
retrieved by _get_log(). We use a real OS file, not an in-memory object,
163
so that it can also capture file IO. When the test completes this file
164
is read into memory and removed from disk.
164
166
There are also convenience functions to invoke bzr's command-line
165
routine, and to build and check bzr trees."""
167
routine, and to build and check bzr trees.
169
In addition to the usual method of overriding tearDown(), this class also
170
allows subclasses to register functions into the _cleanups list, which is
171
run in order as the object is torn down. It's less likely this will be
172
accidentally overlooked.
168
176
_log_file_name = None
171
180
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']
182
self._cleanEnvironment()
180
183
bzrlib.trace.disable_default_logging()
181
self._enable_file_logging()
183
186
def _ndiff_strings(self, a, b):
184
187
"""Return ndiff between two strings containing lines.
213
216
raise AssertionError('pattern "%s" not found in "%s"'
214
217
% (needle_re, haystack))
216
def _enable_file_logging(self):
219
def _startLogFile(self):
220
"""Send bzr and test log messages to a temporary file.
222
The file is removed as the test is torn down.
217
224
fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
219
225
self._log_file = os.fdopen(fileno, 'w+')
221
hdlr = logging.StreamHandler(self._log_file)
222
hdlr.setLevel(logging.DEBUG)
223
hdlr.setFormatter(logging.Formatter('%(levelname)8s %(message)s'))
224
logging.getLogger('').addHandler(hdlr)
225
logging.getLogger('').setLevel(logging.DEBUG)
226
self._log_hdlr = hdlr
226
bzrlib.trace.enable_test_log(self._log_file)
227
227
debug('opened log file %s', name)
229
228
self._log_file_name = name
232
os.environ['HOME'] = self.oldenv
233
if os.environ.get('BZREMAIL') is not None:
234
del os.environ['BZREMAIL']
235
if self.bzr_email is not None:
236
os.environ['BZREMAIL'] = self.bzr_email
237
if os.environ.get('EMAIL') is not None:
238
del os.environ['EMAIL']
239
if self.email is not None:
240
os.environ['EMAIL'] = self.email
241
logging.getLogger('').removeHandler(self._log_hdlr)
242
bzrlib.trace.enable_default_logging()
243
logging.debug('%s teardown', self.id())
229
self.addCleanup(self._finishLogFile)
231
def _finishLogFile(self):
232
"""Finished with the log file.
234
Read contents into memory, close, and delete.
236
bzrlib.trace.disable_test_log()
237
self._log_file.seek(0)
238
self._log_contents = self._log_file.read()
244
239
self._log_file.close()
240
os.remove(self._log_file_name)
241
self._log_file = self._log_file_name = None
243
def addCleanup(self, callable):
244
"""Arrange to run a callable when this case is torn down.
246
Callables are run in the reverse of the order they are registered,
247
ie last-in first-out.
249
if callable in self._cleanups:
250
raise ValueError("cleanup function %r already registered on %s"
252
self._cleanups.append(callable)
254
def _cleanEnvironment(self):
257
'APPDATA': os.getcwd(),
262
self.addCleanup(self._restoreEnvironment)
263
for name, value in new_env.iteritems():
264
self._captureVar(name, value)
267
def _captureVar(self, name, newvalue):
268
"""Set an environment variable, preparing it to be reset when finished."""
269
self.__old_env[name] = os.environ.get(name, None)
271
if name in os.environ:
274
os.environ[name] = newvalue
277
def _restoreVar(name, value):
279
if name in os.environ:
282
os.environ[name] = value
284
def _restoreEnvironment(self):
285
for name, value in self.__old_env.iteritems():
286
self._restoreVar(name, value)
245
290
unittest.TestCase.tearDown(self)
292
def _runCleanups(self):
293
"""Run registered cleanup functions.
295
This should only be called from TestCase.tearDown.
297
for callable in reversed(self._cleanups):
247
300
def log(self, *args):
248
301
logging.debug(*args)
252
305
if self._log_file_name:
253
306
return open(self._log_file_name).read()
308
return self._log_contents
257
def capture(self, cmd):
310
def capture(self, cmd, retcode=0):
258
311
"""Shortcut that splits cmd into words, runs, and returns stdout"""
259
return self.run_bzr_captured(cmd.split())[0]
312
return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
261
314
def run_bzr_captured(self, argv, retcode=0):
262
"""Invoke bzr and return (result, stdout, stderr).
315
"""Invoke bzr and return (stdout, stderr).
264
317
Useful for code that wants to check the contents of the
265
318
output, the way error messages are presented, etc.
418
471
os.mkdir(os.path.join(TestCaseInTempDir.TEST_ROOT, '.bzr'))
474
super(TestCaseInTempDir, self).setUp()
421
475
self._make_test_root()
422
self._currentdir = os.getcwdu()
476
_currentdir = os.getcwdu()
423
477
short_id = self.id().replace('bzrlib.selftest.', '') \
424
478
.replace('__main__.', '')
425
479
self.test_dir = os.path.join(self.TEST_ROOT, short_id)
426
480
os.mkdir(self.test_dir)
427
481
os.chdir(self.test_dir)
428
super(TestCaseInTempDir, self).setUp()
482
os.environ['HOME'] = self.test_dir
483
def _leaveDirectory():
484
os.chdir(_currentdir)
485
self.addCleanup(_leaveDirectory)
431
os.chdir(self._currentdir)
432
super(TestCaseInTempDir, self).tearDown()
434
def build_tree(self, shape):
487
def build_tree(self, shape, line_endings='native'):
435
488
"""Build a test tree according to a pattern.
437
490
shape is a sequence of file specifications. If the final
438
491
character is '/', a directory is created.
440
493
This doesn't add anything to a branch.
494
:param line_endings: Either 'binary' or 'native'
495
in binary mode, exact contents are written
496
in native mode, the line endings match the
497
default platform endings.
442
499
# XXX: It's OK to just create them using forward slashes on windows?
443
500
for name in shape:
444
assert isinstance(name, basestring)
501
self.assert_(isinstance(name, basestring))
445
502
if name[-1] == '/':
446
503
os.mkdir(name[:-1])
505
if line_endings == 'binary':
507
elif line_endings == 'native':
510
raise BzrError('Invalid line ending request %r' % (line_endings,))
449
511
print >>f, "contents of", name
465
527
class MetaTestLog(TestCase):
466
528
def test_logging(self):
467
529
"""Test logs are captured when a test fails."""
468
logging.info('an info message')
469
warning('something looks dodgy...')
470
logging.debug('hello, test is running')
530
self.log('a test message')
531
self.assertContainsRe(self._get_log(), 'a test message\n')
474
534
def filter_suite_by_re(suite, pattern):
505
565
return result.wasSuccessful()
508
def selftest(verbose=False, pattern=".*", stop_on_failure=True):
568
def selftest(verbose=False, pattern=".*", stop_on_failure=True,
509
570
"""Run the whole test suite under the enhanced runner"""
510
571
return run_suite(test_suite(), 'testbzr', verbose=verbose, pattern=pattern,
511
stop_on_failure=stop_on_failure)
572
stop_on_failure=stop_on_failure, keep_output=keep_output)
514
575
def test_suite():
520
581
global MODULES_TO_TEST, MODULES_TO_DOCTEST
583
# FIXME: If these fail to load, e.g. because of a syntax error, the
584
# exception is hidden by unittest. Sucks. Should either fix that or
585
# perhaps import them and pass them to unittest as modules.
522
586
testmod_names = \
523
587
['bzrlib.selftest.MetaTestLog',
588
'bzrlib.selftest.testapi',
524
589
'bzrlib.selftest.testgpg',
525
590
'bzrlib.selftest.testidentitymap',
526
591
'bzrlib.selftest.testinv',
553
618
'bzrlib.selftest.testsampler',
554
619
'bzrlib.selftest.testtransactions',
555
620
'bzrlib.selftest.testtransport',
621
'bzrlib.selftest.testsftp',
556
622
'bzrlib.selftest.testgraph',
557
623
'bzrlib.selftest.testworkingtree',
558
624
'bzrlib.selftest.test_upgrade',
563
629
'bzrlib.selftest.testoptions',
564
630
'bzrlib.selftest.testhttp',
565
631
'bzrlib.selftest.testnonascii',
632
'bzrlib.selftest.testreweave',
633
'bzrlib.selftest.testtsort',
634
'bzrlib.selftest.testtrace',
568
637
for m in (bzrlib.store, bzrlib.inventory, bzrlib.branch,