/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 bzrlib/tests/__init__.py

  • Committer: John Arbash Meinel
  • Date: 2010-09-25 20:08:01 UTC
  • mfrom: (5444 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5445.
  • Revision ID: john@arbash-meinel.com-20100925200801-7uf0ux3uwxo9i3x0
Merge bzr.dev 5444 to resolve some small text conflicts.

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,
114
113
    TestUtil,
115
114
    treeshape,
116
115
    )
117
 
from bzrlib.tests.http_server import HttpServer
118
 
from bzrlib.tests.TestUtil import (
119
 
                          TestSuite,
120
 
                          TestLoader,
121
 
                          )
122
116
from bzrlib.ui import NullProgressView
123
117
from bzrlib.ui.text import TextUIFactory
124
118
import bzrlib.version_info_formats.format_custom
140
134
SUBUNIT_SEEK_SET = 0
141
135
SUBUNIT_SEEK_CUR = 1
142
136
 
 
137
# These are intentionally brought into this namespace. That way plugins, etc
 
138
# can just "from bzrlib.tests import TestCase, TestLoader, etc"
 
139
TestSuite = TestUtil.TestSuite
 
140
TestLoader = TestUtil.TestLoader
143
141
 
144
142
class ExtendedTestResult(testtools.TextTestResult):
145
143
    """Accepts, reports and accumulates the results of running tests.
195
193
        self.count = 0
196
194
        self._overall_start_time = time.time()
197
195
        self._strict = strict
 
196
        self._first_thread_leaker_id = None
 
197
        self._tests_leaking_threads_count = 0
198
198
 
199
199
    def stopTestRun(self):
200
200
        run = self.testsRun
239
239
            ok = self.wasStrictlySuccessful()
240
240
        else:
241
241
            ok = self.wasSuccessful()
242
 
        if TestCase._first_thread_leaker_id:
 
242
        if self._first_thread_leaker_id:
243
243
            self.stream.write(
244
244
                '%s is leaking threads among %d leaking tests.\n' % (
245
 
                TestCase._first_thread_leaker_id,
246
 
                TestCase._leaking_threads_tests))
 
245
                self._first_thread_leaker_id,
 
246
                self._tests_leaking_threads_count))
247
247
            # We don't report the main thread as an active one.
248
248
            self.stream.write(
249
249
                '%d non-main threads were left active in the end.\n'
250
 
                % (TestCase._active_threads - 1))
 
250
                % (len(self._active_threads) - 1))
251
251
 
252
252
    def getDescription(self, test):
253
253
        return test.id()
284
284
        super(ExtendedTestResult, self).startTest(test)
285
285
        if self.count == 0:
286
286
            self.startTests()
 
287
        self.count += 1
287
288
        self.report_test_start(test)
288
289
        test.number = self.count
289
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)
290
295
 
291
296
    def startTests(self):
292
 
        import platform
293
 
        if getattr(sys, 'frozen', None) is None:
294
 
            bzr_path = osutils.realpath(sys.argv[0])
295
 
        else:
296
 
            bzr_path = sys.executable
297
 
        self.stream.write(
298
 
            'bzr selftest: %s\n' % (bzr_path,))
299
 
        self.stream.write(
300
 
            '   %s\n' % (
301
 
                    bzrlib.__path__[0],))
302
 
        self.stream.write(
303
 
            '   bzr-%s python-%s %s\n' % (
304
 
                    bzrlib.version_string,
305
 
                    bzrlib._format_version_tuple(sys.version_info),
306
 
                    platform.platform(aliased=1),
307
 
                    ))
308
 
        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
309
315
 
310
316
    def _recordTestStartTime(self):
311
317
        """Record that a test has started."""
312
318
        self._start_time = time.time()
313
319
 
314
 
    def _cleanupLogFile(self, test):
315
 
        # We can only do this if we have one of our TestCases, not if
316
 
        # we have a doctest.
317
 
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
318
 
        if setKeepLogfile is not None:
319
 
            setKeepLogfile()
320
 
 
321
320
    def addError(self, test, err):
322
321
        """Tell result that test finished with an error.
323
322
 
330
329
        self.report_error(test, err)
331
330
        if self.stop_early:
332
331
            self.stop()
333
 
        self._cleanupLogFile(test)
334
332
 
335
333
    def addFailure(self, test, err):
336
334
        """Tell result that test failed.
344
342
        self.report_failure(test, err)
345
343
        if self.stop_early:
346
344
            self.stop()
347
 
        self._cleanupLogFile(test)
348
345
 
349
346
    def addSuccess(self, test, details=None):
350
347
        """Tell result that test completed successfully.
358
355
                    self._formatTime(benchmark_time),
359
356
                    test.id()))
360
357
        self.report_success(test)
361
 
        self._cleanupLogFile(test)
362
358
        super(ExtendedTestResult, self).addSuccess(test)
363
359
        test._log_contents = ''
364
360
 
402
398
        else:
403
399
            raise errors.BzrError("Unknown whence %r" % whence)
404
400
 
405
 
    def report_cleaning_up(self):
406
 
        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)))
407
432
 
408
433
    def startTestRun(self):
409
434
        self.startTime = time.time()
446
471
        self.pb.finished()
447
472
        super(TextTestResult, self).stopTestRun()
448
473
 
449
 
    def startTestRun(self):
450
 
        super(TextTestResult, self).startTestRun()
 
474
    def report_tests_starting(self):
 
475
        super(TextTestResult, self).report_tests_starting()
451
476
        self.pb.update('[test 0/%d] Starting' % (self.num_tests))
452
477
 
453
 
    def printErrors(self):
454
 
        # clear the pb to make room for the error listing
455
 
        self.pb.clear()
456
 
        super(TextTestResult, self).printErrors()
457
 
 
458
478
    def _progress_prefix_text(self):
459
479
        # the longer this text, the less space we have to show the test
460
480
        # name...
482
502
        return a
483
503
 
484
504
    def report_test_start(self, test):
485
 
        self.count += 1
486
505
        self.pb.update(
487
506
                self._progress_prefix_text()
488
507
                + ' '
515
534
    def report_unsupported(self, test, feature):
516
535
        """test cannot be run because feature is missing."""
517
536
 
518
 
    def report_cleaning_up(self):
519
 
        self.pb.update('Cleaning up')
520
 
 
521
537
 
522
538
class VerboseTestResult(ExtendedTestResult):
523
539
    """Produce long output, with one line per test run plus times"""
530
546
            result = a_string
531
547
        return result.ljust(final_width)
532
548
 
533
 
    def startTestRun(self):
534
 
        super(VerboseTestResult, self).startTestRun()
 
549
    def report_tests_starting(self):
535
550
        self.stream.write('running %d tests...\n' % self.num_tests)
 
551
        super(VerboseTestResult, self).report_tests_starting()
536
552
 
537
553
    def report_test_start(self, test):
538
 
        self.count += 1
539
554
        name = self._shortened_test_description(test)
540
555
        width = osutils.terminal_width()
541
556
        if width is not None:
791
806
    routine, and to build and check bzr trees.
792
807
 
793
808
    In addition to the usual method of overriding tearDown(), this class also
794
 
    allows subclasses to register functions into the _cleanups list, which is
 
809
    allows subclasses to register cleanup functions via addCleanup, which are
795
810
    run in order as the object is torn down.  It's less likely this will be
796
811
    accidentally overlooked.
797
812
    """
798
813
 
799
 
    _active_threads = None
800
 
    _leaking_threads_tests = 0
801
 
    _first_thread_leaker_id = None
802
 
    _log_file_name = None
 
814
    _log_file = None
803
815
    # record lsprof data when performing benchmark calls.
804
816
    _gather_lsprof_in_benchmarks = False
805
817
 
806
818
    def __init__(self, methodName='testMethod'):
807
819
        super(TestCase, self).__init__(methodName)
808
 
        self._cleanups = []
809
820
        self._directory_isolation = True
810
821
        self.exception_handlers.insert(0,
811
822
            (UnavailableFeature, self._do_unsupported_or_skip))
829
840
        self._track_transports()
830
841
        self._track_locks()
831
842
        self._clear_debug_flags()
832
 
        TestCase._active_threads = threading.activeCount()
833
 
        self.addCleanup(self._check_leaked_threads)
834
843
 
835
844
    def debug(self):
836
845
        # debug a frame up.
853
862
        if name in details:
854
863
            del details[name]
855
864
 
856
 
    def _check_leaked_threads(self):
857
 
        active = threading.activeCount()
858
 
        leaked_threads = active - TestCase._active_threads
859
 
        TestCase._active_threads = active
860
 
        # If some tests make the number of threads *decrease*, we'll consider
861
 
        # that they are just observing old threads dieing, not agressively kill
862
 
        # random threads. So we don't report these tests as leaking. The risk
863
 
        # is that we have false positives that way (the test see 2 threads
864
 
        # going away but leak one) but it seems less likely than the actual
865
 
        # false positives (the test see threads going away and does not leak).
866
 
        if leaked_threads > 0:
867
 
            TestCase._leaking_threads_tests += 1
868
 
            if TestCase._first_thread_leaker_id is None:
869
 
                TestCase._first_thread_leaker_id = self.id()
870
 
 
871
865
    def _clear_debug_flags(self):
872
866
        """Prevent externally set debug flags affecting tests.
873
867
 
1473
1467
 
1474
1468
        The file is removed as the test is torn down.
1475
1469
        """
1476
 
        fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
1477
 
        self._log_file = os.fdopen(fileno, 'w+')
 
1470
        self._log_file = StringIO()
1478
1471
        self._log_memento = bzrlib.trace.push_log_file(self._log_file)
1479
 
        self._log_file_name = name
1480
1472
        self.addCleanup(self._finishLogFile)
1481
1473
 
1482
1474
    def _finishLogFile(self):
1504
1496
        """
1505
1497
        debug.debug_flags.discard('strict_locks')
1506
1498
 
1507
 
    def addCleanup(self, callable, *args, **kwargs):
1508
 
        """Arrange to run a callable when this case is torn down.
1509
 
 
1510
 
        Callables are run in the reverse of the order they are registered,
1511
 
        ie last-in first-out.
1512
 
        """
1513
 
        self._cleanups.append((callable, args, kwargs))
1514
 
 
1515
1499
    def overrideAttr(self, obj, attr_name, new=_unitialized_attr):
1516
1500
        """Overrides an object attribute restoring it after the test.
1517
1501
 
1712
1696
                unicodestr = self._log_contents.decode('utf8', 'replace')
1713
1697
                self._log_contents = unicodestr.encode('utf8')
1714
1698
            return self._log_contents
1715
 
        import bzrlib.trace
1716
 
        if bzrlib.trace._trace_file:
1717
 
            # flush the log file, to get all content
1718
 
            bzrlib.trace._trace_file.flush()
1719
 
        if self._log_file_name is not None:
1720
 
            logfile = open(self._log_file_name)
1721
 
            try:
1722
 
                log_contents = logfile.read()
1723
 
            finally:
1724
 
                logfile.close()
 
1699
        if self._log_file is not None:
 
1700
            log_contents = self._log_file.getvalue()
1725
1701
            try:
1726
1702
                log_contents.decode('utf8')
1727
1703
            except UnicodeDecodeError:
1728
1704
                unicodestr = log_contents.decode('utf8', 'replace')
1729
1705
                log_contents = unicodestr.encode('utf8')
1730
1706
            if not keep_log_file:
1731
 
                close_attempts = 0
1732
 
                max_close_attempts = 100
1733
 
                first_close_error = None
1734
 
                while close_attempts < max_close_attempts:
1735
 
                    close_attempts += 1
1736
 
                    try:
1737
 
                        self._log_file.close()
1738
 
                    except IOError, ioe:
1739
 
                        if ioe.errno is None:
1740
 
                            # No errno implies 'close() called during
1741
 
                            # concurrent operation on the same file object', so
1742
 
                            # retry.  Probably a thread is trying to write to
1743
 
                            # the log file.
1744
 
                            if first_close_error is None:
1745
 
                                first_close_error = ioe
1746
 
                            continue
1747
 
                        raise
1748
 
                    else:
1749
 
                        break
1750
 
                if close_attempts > 1:
1751
 
                    sys.stderr.write(
1752
 
                        'Unable to close log file on first attempt, '
1753
 
                        'will retry: %s\n' % (first_close_error,))
1754
 
                    if close_attempts == max_close_attempts:
1755
 
                        sys.stderr.write(
1756
 
                            'Unable to close log file after %d attempts.\n'
1757
 
                            % (max_close_attempts,))
1758
1707
                self._log_file = None
1759
1708
                # Permit multiple calls to get_log until we clean it up in
1760
1709
                # finishLogFile
1761
1710
                self._log_contents = log_contents
1762
 
                try:
1763
 
                    os.remove(self._log_file_name)
1764
 
                except OSError, e:
1765
 
                    if sys.platform == 'win32' and e.errno == errno.EACCES:
1766
 
                        sys.stderr.write(('Unable to delete log file '
1767
 
                                             ' %r\n' % self._log_file_name))
1768
 
                    else:
1769
 
                        raise
1770
 
                self._log_file_name = None
1771
1711
            return log_contents
1772
1712
        else:
1773
 
            return "No log file content and no log file name."
 
1713
            return "No log file content."
1774
1714
 
1775
1715
    def get_log(self):
1776
1716
        """Get a unicode string containing the log from bzrlib.trace.
1991
1931
            variables. A value of None will unset the env variable.
1992
1932
            The values must be strings. The change will only occur in the
1993
1933
            child, so you don't need to fix the environment after running.
1994
 
        :param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
1995
 
            is not available.
 
1934
        :param skip_if_plan_to_signal: raise TestSkipped when true and system
 
1935
            doesn't support signalling subprocesses.
1996
1936
        :param allow_plugins: If False (default) pass --no-plugins to bzr.
1997
1937
 
1998
1938
        :returns: Popen object for the started process.
1999
1939
        """
2000
1940
        if skip_if_plan_to_signal:
2001
 
            if not getattr(os, 'kill', None):
2002
 
                raise TestSkipped("os.kill not available.")
 
1941
            if os.name != "posix":
 
1942
                raise TestSkipped("Sending signals not supported")
2003
1943
 
2004
1944
        if env_changes is None:
2005
1945
            env_changes = {}
2483
2423
 
2484
2424
    def setUp(self):
2485
2425
        super(TestCaseWithMemoryTransport, self).setUp()
 
2426
        # Ensure that ConnectedTransport doesn't leak sockets
 
2427
        def get_transport_with_cleanup(*args, **kwargs):
 
2428
            t = orig_get_transport(*args, **kwargs)
 
2429
            if isinstance(t, _mod_transport.ConnectedTransport):
 
2430
                self.addCleanup(t.disconnect)
 
2431
            return t
 
2432
 
 
2433
        orig_get_transport = self.overrideAttr(_mod_transport, 'get_transport',
 
2434
                                               get_transport_with_cleanup)
2486
2435
        self._make_test_root()
2487
2436
        self.addCleanup(os.chdir, os.getcwdu())
2488
2437
        self.makeAndChdirToTestDir()
2780
2729
    """
2781
2730
 
2782
2731
    def setUp(self):
 
2732
        from bzrlib.tests import http_server
2783
2733
        super(ChrootedTestCase, self).setUp()
2784
2734
        if not self.vfs_transport_factory == memory.MemoryServer:
2785
 
            self.transport_readonly_server = HttpServer
 
2735
            self.transport_readonly_server = http_server.HttpServer
2786
2736
 
2787
2737
 
2788
2738
def condition_id_re(pattern):
3049
2999
 
3050
3000
 
3051
3001
def fork_decorator(suite):
 
3002
    if getattr(os, "fork", None) is None:
 
3003
        raise errors.BzrCommandError("platform does not support fork,"
 
3004
            " try --parallel=subprocess instead.")
3052
3005
    concurrency = osutils.local_concurrency()
3053
3006
    if concurrency == 1:
3054
3007
        return suite
3109
3062
    return suite
3110
3063
 
3111
3064
 
3112
 
class TestDecorator(TestSuite):
 
3065
class TestDecorator(TestUtil.TestSuite):
3113
3066
    """A decorator for TestCase/TestSuite objects.
3114
3067
    
3115
3068
    Usually, subclasses should override __iter__(used when flattening test
3118
3071
    """
3119
3072
 
3120
3073
    def __init__(self, suite):
3121
 
        TestSuite.__init__(self)
 
3074
        TestUtil.TestSuite.__init__(self)
3122
3075
        self.addTest(suite)
3123
3076
 
3124
3077
    def countTestCases(self):
3292
3245
 
3293
3246
    test_blocks = partition_tests(suite, concurrency)
3294
3247
    for process_tests in test_blocks:
3295
 
        process_suite = TestSuite()
 
3248
        process_suite = TestUtil.TestSuite()
3296
3249
        process_suite.addTests(process_tests)
3297
3250
        c2pread, c2pwrite = os.pipe()
3298
3251
        pid = os.fork()
3453
3406
#                           rather than failing tests. And no longer raise
3454
3407
#                           LockContention when fctnl locks are not being used
3455
3408
#                           with proper exclusion rules.
 
3409
#   -Ethreads               Will display thread ident at creation/join time to
 
3410
#                           help track thread leaks
3456
3411
selftest_debug_flags = set()
3457
3412
 
3458
3413
 
3694
3649
        'bzrlib.tests.doc_generate',
3695
3650
        'bzrlib.tests.per_branch',
3696
3651
        'bzrlib.tests.per_bzrdir',
3697
 
        'bzrlib.tests.per_bzrdir_colo',
 
3652
        'bzrlib.tests.per_controldir',
 
3653
        'bzrlib.tests.per_controldir_colo',
3698
3654
        'bzrlib.tests.per_foreign_vcs',
3699
3655
        'bzrlib.tests.per_interrepository',
3700
3656
        'bzrlib.tests.per_intertree',
3713
3669
        'bzrlib.tests.per_workingtree',
3714
3670
        'bzrlib.tests.test__annotator',
3715
3671
        'bzrlib.tests.test__bencode',
 
3672
        'bzrlib.tests.test__btree_serializer',
3716
3673
        'bzrlib.tests.test__chk_map',
3717
3674
        'bzrlib.tests.test__dirstate_helpers',
3718
3675
        'bzrlib.tests.test__groupcompress',
3851
3808
        'bzrlib.tests.test_switch',
3852
3809
        'bzrlib.tests.test_symbol_versioning',
3853
3810
        'bzrlib.tests.test_tag',
 
3811
        'bzrlib.tests.test_test_server',
3854
3812
        'bzrlib.tests.test_testament',
3855
3813
        'bzrlib.tests.test_textfile',
3856
3814
        'bzrlib.tests.test_textmerge',
4047
4005
    ...     bzrlib.tests.test_sampler.DemoTest('test_nothing'),
4048
4006
    ...     [('one', dict(param=1)),
4049
4007
    ...      ('two', dict(param=2))],
4050
 
    ...     TestSuite())
 
4008
    ...     TestUtil.TestSuite())
4051
4009
    >>> tests = list(iter_suite_tests(r))
4052
4010
    >>> len(tests)
4053
4011
    2
4102
4060
    """
4103
4061
    new_test = copy.copy(test)
4104
4062
    new_test.id = lambda: new_id
 
4063
    # XXX: Workaround <https://bugs.launchpad.net/testtools/+bug/637725>, which
 
4064
    # causes cloned tests to share the 'details' dict.  This makes it hard to
 
4065
    # read the test output for parameterized tests, because tracebacks will be
 
4066
    # associated with irrelevant tests.
 
4067
    try:
 
4068
        details = new_test._TestCase__details
 
4069
    except AttributeError:
 
4070
        # must be a different version of testtools than expected.  Do nothing.
 
4071
        pass
 
4072
    else:
 
4073
        # Reset the '__details' dict.
 
4074
        new_test._TestCase__details = {}
4105
4075
    return new_test
4106
4076
 
4107
4077