~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Parth Malwankar
  • Date: 2010-09-24 12:53:00 UTC
  • mfrom: (5443 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5444.
  • Revision ID: parth.malwankar@gmail.com-20100924125300-70sg2t3q03bcuqpm
merged trunk and moved NEWS entry to correct section

Show diffs side-by-side

added added

removed removed

Lines of Context:
36
36
import errno
37
37
import itertools
38
38
import logging
39
 
import math
40
39
import os
 
40
import platform
41
41
import pprint
42
42
import random
43
43
import re
71
71
    lock as _mod_lock,
72
72
    memorytree,
73
73
    osutils,
74
 
    progress,
75
74
    ui,
76
75
    urlutils,
77
76
    registry,
194
193
        self.count = 0
195
194
        self._overall_start_time = time.time()
196
195
        self._strict = strict
 
196
        self._first_thread_leaker_id = None
 
197
        self._tests_leaking_threads_count = 0
197
198
 
198
199
    def stopTestRun(self):
199
200
        run = self.testsRun
238
239
            ok = self.wasStrictlySuccessful()
239
240
        else:
240
241
            ok = self.wasSuccessful()
241
 
        if TestCase._first_thread_leaker_id:
 
242
        if self._first_thread_leaker_id:
242
243
            self.stream.write(
243
244
                '%s is leaking threads among %d leaking tests.\n' % (
244
 
                TestCase._first_thread_leaker_id,
245
 
                TestCase._leaking_threads_tests))
 
245
                self._first_thread_leaker_id,
 
246
                self._tests_leaking_threads_count))
246
247
            # We don't report the main thread as an active one.
247
248
            self.stream.write(
248
249
                '%d non-main threads were left active in the end.\n'
249
 
                % (TestCase._active_threads - 1))
 
250
                % (len(self._active_threads) - 1))
250
251
 
251
252
    def getDescription(self, test):
252
253
        return test.id()
283
284
        super(ExtendedTestResult, self).startTest(test)
284
285
        if self.count == 0:
285
286
            self.startTests()
 
287
        self.count += 1
286
288
        self.report_test_start(test)
287
289
        test.number = self.count
288
290
        self._recordTestStartTime()
 
291
        # Only check for thread leaks if the test case supports cleanups
 
292
        addCleanup = getattr(test, "addCleanup", None)
 
293
        if addCleanup is not None:
 
294
            addCleanup(self._check_leaked_threads, test)
289
295
 
290
296
    def startTests(self):
291
 
        import platform
292
 
        if getattr(sys, 'frozen', None) is None:
293
 
            bzr_path = osutils.realpath(sys.argv[0])
294
 
        else:
295
 
            bzr_path = sys.executable
296
 
        self.stream.write(
297
 
            'bzr selftest: %s\n' % (bzr_path,))
298
 
        self.stream.write(
299
 
            '   %s\n' % (
300
 
                    bzrlib.__path__[0],))
301
 
        self.stream.write(
302
 
            '   bzr-%s python-%s %s\n' % (
303
 
                    bzrlib.version_string,
304
 
                    bzrlib._format_version_tuple(sys.version_info),
305
 
                    platform.platform(aliased=1),
306
 
                    ))
307
 
        self.stream.write('\n')
 
297
        self.report_tests_starting()
 
298
        self._active_threads = threading.enumerate()
 
299
 
 
300
    def _check_leaked_threads(self, test):
 
301
        """See if any threads have leaked since last call
 
302
 
 
303
        A sample of live threads is stored in the _active_threads attribute,
 
304
        when this method runs it compares the current live threads and any not
 
305
        in the previous sample are treated as having leaked.
 
306
        """
 
307
        now_active_threads = set(threading.enumerate())
 
308
        threads_leaked = now_active_threads.difference(self._active_threads)
 
309
        if threads_leaked:
 
310
            self._report_thread_leak(test, threads_leaked, now_active_threads)
 
311
            self._tests_leaking_threads_count += 1
 
312
            if self._first_thread_leaker_id is None:
 
313
                self._first_thread_leaker_id = test.id()
 
314
            self._active_threads = now_active_threads
308
315
 
309
316
    def _recordTestStartTime(self):
310
317
        """Record that a test has started."""
311
318
        self._start_time = time.time()
312
319
 
313
 
    def _cleanupLogFile(self, test):
314
 
        # We can only do this if we have one of our TestCases, not if
315
 
        # we have a doctest.
316
 
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
317
 
        if setKeepLogfile is not None:
318
 
            setKeepLogfile()
319
 
 
320
320
    def addError(self, test, err):
321
321
        """Tell result that test finished with an error.
322
322
 
329
329
        self.report_error(test, err)
330
330
        if self.stop_early:
331
331
            self.stop()
332
 
        self._cleanupLogFile(test)
333
332
 
334
333
    def addFailure(self, test, err):
335
334
        """Tell result that test failed.
343
342
        self.report_failure(test, err)
344
343
        if self.stop_early:
345
344
            self.stop()
346
 
        self._cleanupLogFile(test)
347
345
 
348
346
    def addSuccess(self, test, details=None):
349
347
        """Tell result that test completed successfully.
357
355
                    self._formatTime(benchmark_time),
358
356
                    test.id()))
359
357
        self.report_success(test)
360
 
        self._cleanupLogFile(test)
361
358
        super(ExtendedTestResult, self).addSuccess(test)
362
359
        test._log_contents = ''
363
360
 
401
398
        else:
402
399
            raise errors.BzrError("Unknown whence %r" % whence)
403
400
 
404
 
    def report_cleaning_up(self):
405
 
        pass
 
401
    def report_tests_starting(self):
 
402
        """Display information before the test run begins"""
 
403
        if getattr(sys, 'frozen', None) is None:
 
404
            bzr_path = osutils.realpath(sys.argv[0])
 
405
        else:
 
406
            bzr_path = sys.executable
 
407
        self.stream.write(
 
408
            'bzr selftest: %s\n' % (bzr_path,))
 
409
        self.stream.write(
 
410
            '   %s\n' % (
 
411
                    bzrlib.__path__[0],))
 
412
        self.stream.write(
 
413
            '   bzr-%s python-%s %s\n' % (
 
414
                    bzrlib.version_string,
 
415
                    bzrlib._format_version_tuple(sys.version_info),
 
416
                    platform.platform(aliased=1),
 
417
                    ))
 
418
        self.stream.write('\n')
 
419
 
 
420
    def report_test_start(self, test):
 
421
        """Display information on the test just about to be run"""
 
422
 
 
423
    def _report_thread_leak(self, test, leaked_threads, active_threads):
 
424
        """Display information on a test that leaked one or more threads"""
 
425
        # GZ 2010-09-09: A leak summary reported separately from the general
 
426
        #                thread debugging would be nice. Tests under subunit
 
427
        #                need something not using stream, perhaps adding a
 
428
        #                testtools details object would be fitting.
 
429
        if 'threads' in selftest_debug_flags:
 
430
            self.stream.write('%s is leaking, active is now %d\n' %
 
431
                (test.id(), len(active_threads)))
406
432
 
407
433
    def startTestRun(self):
408
434
        self.startTime = time.time()
445
471
        self.pb.finished()
446
472
        super(TextTestResult, self).stopTestRun()
447
473
 
448
 
    def startTestRun(self):
449
 
        super(TextTestResult, self).startTestRun()
 
474
    def report_tests_starting(self):
 
475
        super(TextTestResult, self).report_tests_starting()
450
476
        self.pb.update('[test 0/%d] Starting' % (self.num_tests))
451
477
 
452
 
    def printErrors(self):
453
 
        # clear the pb to make room for the error listing
454
 
        self.pb.clear()
455
 
        super(TextTestResult, self).printErrors()
456
 
 
457
478
    def _progress_prefix_text(self):
458
479
        # the longer this text, the less space we have to show the test
459
480
        # name...
481
502
        return a
482
503
 
483
504
    def report_test_start(self, test):
484
 
        self.count += 1
485
505
        self.pb.update(
486
506
                self._progress_prefix_text()
487
507
                + ' '
514
534
    def report_unsupported(self, test, feature):
515
535
        """test cannot be run because feature is missing."""
516
536
 
517
 
    def report_cleaning_up(self):
518
 
        self.pb.update('Cleaning up')
519
 
 
520
537
 
521
538
class VerboseTestResult(ExtendedTestResult):
522
539
    """Produce long output, with one line per test run plus times"""
529
546
            result = a_string
530
547
        return result.ljust(final_width)
531
548
 
532
 
    def startTestRun(self):
533
 
        super(VerboseTestResult, self).startTestRun()
 
549
    def report_tests_starting(self):
534
550
        self.stream.write('running %d tests...\n' % self.num_tests)
 
551
        super(VerboseTestResult, self).report_tests_starting()
535
552
 
536
553
    def report_test_start(self, test):
537
 
        self.count += 1
538
554
        name = self._shortened_test_description(test)
539
555
        width = osutils.terminal_width()
540
556
        if width is not None:
790
806
    routine, and to build and check bzr trees.
791
807
 
792
808
    In addition to the usual method of overriding tearDown(), this class also
793
 
    allows subclasses to register functions into the _cleanups list, which is
 
809
    allows subclasses to register cleanup functions via addCleanup, which are
794
810
    run in order as the object is torn down.  It's less likely this will be
795
811
    accidentally overlooked.
796
812
    """
797
813
 
798
 
    _active_threads = None
799
 
    _leaking_threads_tests = 0
800
 
    _first_thread_leaker_id = None
801
814
    _log_file = None
802
815
    # record lsprof data when performing benchmark calls.
803
816
    _gather_lsprof_in_benchmarks = False
804
817
 
805
818
    def __init__(self, methodName='testMethod'):
806
819
        super(TestCase, self).__init__(methodName)
807
 
        self._cleanups = []
808
820
        self._directory_isolation = True
809
821
        self.exception_handlers.insert(0,
810
822
            (UnavailableFeature, self._do_unsupported_or_skip))
828
840
        self._track_transports()
829
841
        self._track_locks()
830
842
        self._clear_debug_flags()
831
 
        TestCase._active_threads = threading.activeCount()
832
 
        self.addCleanup(self._check_leaked_threads)
833
843
 
834
844
    def debug(self):
835
845
        # debug a frame up.
836
846
        import pdb
837
847
        pdb.Pdb().set_trace(sys._getframe().f_back)
838
848
 
839
 
    def _check_leaked_threads(self):
840
 
        active = threading.activeCount()
841
 
        leaked_threads = active - TestCase._active_threads
842
 
        TestCase._active_threads = active
843
 
        # If some tests make the number of threads *decrease*, we'll consider
844
 
        # that they are just observing old threads dieing, not agressively kill
845
 
        # random threads. So we don't report these tests as leaking. The risk
846
 
        # is that we have false positives that way (the test see 2 threads
847
 
        # going away but leak one) but it seems less likely than the actual
848
 
        # false positives (the test see threads going away and does not leak).
849
 
        if leaked_threads > 0:
850
 
            if 'threads' in selftest_debug_flags:
851
 
                print '%s is leaking, active is now %d' % (self.id(), active)
852
 
            TestCase._leaking_threads_tests += 1
853
 
            if TestCase._first_thread_leaker_id is None:
854
 
                TestCase._first_thread_leaker_id = self.id()
855
 
 
856
849
    def _clear_debug_flags(self):
857
850
        """Prevent externally set debug flags affecting tests.
858
851
 
1487
1480
        """
1488
1481
        debug.debug_flags.discard('strict_locks')
1489
1482
 
1490
 
    def addCleanup(self, callable, *args, **kwargs):
1491
 
        """Arrange to run a callable when this case is torn down.
1492
 
 
1493
 
        Callables are run in the reverse of the order they are registered,
1494
 
        ie last-in first-out.
1495
 
        """
1496
 
        self._cleanups.append((callable, args, kwargs))
1497
 
 
1498
1483
    def overrideAttr(self, obj, attr_name, new=_unitialized_attr):
1499
1484
        """Overrides an object attribute restoring it after the test.
1500
1485
 
2970
2955
 
2971
2956
 
2972
2957
def fork_decorator(suite):
 
2958
    if getattr(os, "fork", None) is None:
 
2959
        raise errors.BzrCommandError("platform does not support fork,"
 
2960
            " try --parallel=subprocess instead.")
2973
2961
    concurrency = osutils.local_concurrency()
2974
2962
    if concurrency == 1:
2975
2963
        return suite
4028
4016
    """
4029
4017
    new_test = copy.copy(test)
4030
4018
    new_test.id = lambda: new_id
 
4019
    # XXX: Workaround <https://bugs.launchpad.net/testtools/+bug/637725>, which
 
4020
    # causes cloned tests to share the 'details' dict.  This makes it hard to
 
4021
    # read the test output for parameterized tests, because tracebacks will be
 
4022
    # associated with irrelevant tests.
 
4023
    try:
 
4024
        details = new_test._TestCase__details
 
4025
    except AttributeError:
 
4026
        # must be a different version of testtools than expected.  Do nothing.
 
4027
        pass
 
4028
    else:
 
4029
        # Reset the '__details' dict.
 
4030
        new_test._TestCase__details = {}
4031
4031
    return new_test
4032
4032
 
4033
4033