/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: Jelmer Vernooij
  • Date: 2009-03-28 14:24:46 UTC
  • mfrom: (4211 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4212.
  • Revision ID: jelmer@samba.org-20090328142446-vqi0ksswdurga631
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
 
18
18
# TODO: Perhaps there should be an API to find out if bzr running under the
33
33
import doctest
34
34
import errno
35
35
import logging
 
36
import math
36
37
import os
37
38
from pprint import pformat
38
39
import random
39
40
import re
40
41
import shlex
41
42
import stat
42
 
from subprocess import Popen, PIPE
 
43
from subprocess import Popen, PIPE, STDOUT
43
44
import sys
44
45
import tempfile
45
46
import threading
77
78
from bzrlib.merge import merge_inner
78
79
import bzrlib.merge3
79
80
import bzrlib.plugin
80
 
from bzrlib.smart import client, server
 
81
from bzrlib.smart import client, request, server
81
82
import bzrlib.store
82
83
from bzrlib import symbol_versioning
83
84
from bzrlib.symbol_versioning import (
543
544
                run += 1
544
545
            actionTaken = "Listed"
545
546
        else:
546
 
            test.run(result)
 
547
            try:
 
548
                from testtools import ThreadsafeForwardingResult
 
549
            except ImportError:
 
550
                test.run(result)
 
551
            else:
 
552
                if type(result) == ThreadsafeForwardingResult:
 
553
                    test.run(BZRTransformingResult(result))
 
554
                else:
 
555
                    test.run(result)
547
556
            run = result.testsRun
548
557
            actionTaken = "Ran"
549
558
        stopTime = time.time()
589
598
    if isinstance(suite, unittest.TestCase):
590
599
        yield suite
591
600
    elif isinstance(suite, unittest.TestSuite):
592
 
        for item in suite._tests:
 
601
        for item in suite:
593
602
            for r in iter_suite_tests(item):
594
603
                yield r
595
604
    else:
827
836
        for key, factory in hooks.known_hooks.items():
828
837
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
829
838
            setattr(parent, name, factory())
 
839
        # this hook should always be installed
 
840
        request._install_hook()
830
841
 
831
842
    def _silenceUI(self):
832
843
        """Turn off UI for duration of test"""
1250
1261
            # bzr now uses the Win32 API and doesn't rely on APPDATA, but the
1251
1262
            # tests do check our impls match APPDATA
1252
1263
            'BZR_EDITOR': None, # test_msgeditor manipulates this variable
 
1264
            'VISUAL': None,
 
1265
            'EDITOR': None,
1253
1266
            'BZR_EMAIL': None,
1254
1267
            'BZREMAIL': None, # may still be present in the environment
1255
1268
            'EMAIL': None,
2223
2236
        For TestCaseInTempDir we create a temporary directory based on the test
2224
2237
        name and then create two subdirs - test and home under it.
2225
2238
        """
2226
 
        name_prefix = osutils.pathjoin(self.TEST_ROOT, self._getTestDirPrefix())
 
2239
        name_prefix = osutils.pathjoin(TestCaseWithMemoryTransport.TEST_ROOT,
 
2240
            self._getTestDirPrefix())
2227
2241
        name = name_prefix
2228
2242
        for i in range(100):
2229
2243
            if os.path.exists(name):
2247
2261
        self.addCleanup(self.deleteTestDir)
2248
2262
 
2249
2263
    def deleteTestDir(self):
2250
 
        os.chdir(self.TEST_ROOT)
 
2264
        os.chdir(TestCaseWithMemoryTransport.TEST_ROOT)
2251
2265
        _rmtree_temp_dir(self.test_base_dir)
2252
2266
 
2253
2267
    def build_tree(self, shape, line_endings='binary', transport=None):
2432
2446
    :param pattern: A regular expression string.
2433
2447
    :return: A callable that returns True if the re matches.
2434
2448
    """
2435
 
    filter_re = re.compile(pattern)
 
2449
    filter_re = osutils.re_compile_checked(pattern, 0,
 
2450
        'test filter')
2436
2451
    def condition(test):
2437
2452
        test_id = test.id()
2438
2453
        return filter_re.search(test_id)
2623
2638
              random_seed=None,
2624
2639
              exclude_pattern=None,
2625
2640
              strict=False,
2626
 
              runner_class=None):
 
2641
              runner_class=None,
 
2642
              suite_decorators=None):
2627
2643
    """Run a test suite for bzr selftest.
2628
2644
 
2629
2645
    :param runner_class: The class of runner to use. Must support the
2645
2661
                            list_only=list_only,
2646
2662
                            )
2647
2663
    runner.stop_on_failure=stop_on_failure
2648
 
    # Initialise the random number generator and display the seed used.
2649
 
    # We convert the seed to a long to make it reuseable across invocations.
2650
 
    random_order = False
2651
 
    if random_seed is not None:
2652
 
        random_order = True
2653
 
        if random_seed == "now":
2654
 
            random_seed = long(time.time())
 
2664
    # built in decorator factories:
 
2665
    decorators = [
 
2666
        random_order(random_seed, runner),
 
2667
        exclude_tests(exclude_pattern),
 
2668
        ]
 
2669
    if matching_tests_first:
 
2670
        decorators.append(tests_first(pattern))
 
2671
    else:
 
2672
        decorators.append(filter_tests(pattern))
 
2673
    if suite_decorators:
 
2674
        decorators.extend(suite_decorators)
 
2675
    for decorator in decorators:
 
2676
        suite = decorator(suite)
 
2677
    result = runner.run(suite)
 
2678
    if strict:
 
2679
        return result.wasStrictlySuccessful()
 
2680
    else:
 
2681
        return result.wasSuccessful()
 
2682
 
 
2683
 
 
2684
# A registry where get() returns a suite decorator.
 
2685
parallel_registry = registry.Registry()
 
2686
def fork_decorator(suite):
 
2687
    concurrency = local_concurrency()
 
2688
    if concurrency == 1:
 
2689
        return suite
 
2690
    from testtools import ConcurrentTestSuite
 
2691
    return ConcurrentTestSuite(suite, fork_for_tests)
 
2692
parallel_registry.register('fork', fork_decorator)
 
2693
def subprocess_decorator(suite):
 
2694
    concurrency = local_concurrency()
 
2695
    if concurrency == 1:
 
2696
        return suite
 
2697
    from testtools import ConcurrentTestSuite
 
2698
    return ConcurrentTestSuite(suite, reinvoke_for_tests)
 
2699
parallel_registry.register('subprocess', subprocess_decorator)
 
2700
 
 
2701
 
 
2702
def exclude_tests(exclude_pattern):
 
2703
    """Return a test suite decorator that excludes tests."""
 
2704
    if exclude_pattern is None:
 
2705
        return identity_decorator
 
2706
    def decorator(suite):
 
2707
        return ExcludeDecorator(suite, exclude_pattern)
 
2708
    return decorator
 
2709
 
 
2710
 
 
2711
def filter_tests(pattern):
 
2712
    if pattern == '.*':
 
2713
        return identity_decorator
 
2714
    def decorator(suite):
 
2715
        return FilterTestsDecorator(suite, pattern)
 
2716
    return decorator
 
2717
 
 
2718
 
 
2719
def random_order(random_seed, runner):
 
2720
    """Return a test suite decorator factory for randomising tests order.
 
2721
    
 
2722
    :param random_seed: now, a string which casts to a long, or a long.
 
2723
    :param runner: A test runner with a stream attribute to report on.
 
2724
    """
 
2725
    if random_seed is None:
 
2726
        return identity_decorator
 
2727
    def decorator(suite):
 
2728
        return RandomDecorator(suite, random_seed, runner.stream)
 
2729
    return decorator
 
2730
 
 
2731
 
 
2732
def tests_first(pattern):
 
2733
    if pattern == '.*':
 
2734
        return identity_decorator
 
2735
    def decorator(suite):
 
2736
        return TestFirstDecorator(suite, pattern)
 
2737
    return decorator
 
2738
 
 
2739
 
 
2740
def identity_decorator(suite):
 
2741
    """Return suite."""
 
2742
    return suite
 
2743
 
 
2744
 
 
2745
class TestDecorator(TestSuite):
 
2746
    """A decorator for TestCase/TestSuite objects.
 
2747
    
 
2748
    Usually, subclasses should override __iter__(used when flattening test
 
2749
    suites), which we do to filter, reorder, parallelise and so on, run() and
 
2750
    debug().
 
2751
    """
 
2752
 
 
2753
    def __init__(self, suite):
 
2754
        TestSuite.__init__(self)
 
2755
        self.addTest(suite)
 
2756
 
 
2757
    def countTestCases(self):
 
2758
        cases = 0
 
2759
        for test in self:
 
2760
            cases += test.countTestCases()
 
2761
        return cases
 
2762
 
 
2763
    def debug(self):
 
2764
        for test in self:
 
2765
            test.debug()
 
2766
 
 
2767
    def run(self, result):
 
2768
        # Use iteration on self, not self._tests, to allow subclasses to hook
 
2769
        # into __iter__.
 
2770
        for test in self:
 
2771
            if result.shouldStop:
 
2772
                break
 
2773
            test.run(result)
 
2774
        return result
 
2775
 
 
2776
 
 
2777
class ExcludeDecorator(TestDecorator):
 
2778
    """A decorator which excludes test matching an exclude pattern."""
 
2779
 
 
2780
    def __init__(self, suite, exclude_pattern):
 
2781
        TestDecorator.__init__(self, suite)
 
2782
        self.exclude_pattern = exclude_pattern
 
2783
        self.excluded = False
 
2784
 
 
2785
    def __iter__(self):
 
2786
        if self.excluded:
 
2787
            return iter(self._tests)
 
2788
        self.excluded = True
 
2789
        suite = exclude_tests_by_re(self, self.exclude_pattern)
 
2790
        del self._tests[:]
 
2791
        self.addTests(suite)
 
2792
        return iter(self._tests)
 
2793
 
 
2794
 
 
2795
class FilterTestsDecorator(TestDecorator):
 
2796
    """A decorator which filters tests to those matching a pattern."""
 
2797
 
 
2798
    def __init__(self, suite, pattern):
 
2799
        TestDecorator.__init__(self, suite)
 
2800
        self.pattern = pattern
 
2801
        self.filtered = False
 
2802
 
 
2803
    def __iter__(self):
 
2804
        if self.filtered:
 
2805
            return iter(self._tests)
 
2806
        self.filtered = True
 
2807
        suite = filter_suite_by_re(self, self.pattern)
 
2808
        del self._tests[:]
 
2809
        self.addTests(suite)
 
2810
        return iter(self._tests)
 
2811
 
 
2812
 
 
2813
class RandomDecorator(TestDecorator):
 
2814
    """A decorator which randomises the order of its tests."""
 
2815
 
 
2816
    def __init__(self, suite, random_seed, stream):
 
2817
        TestDecorator.__init__(self, suite)
 
2818
        self.random_seed = random_seed
 
2819
        self.randomised = False
 
2820
        self.stream = stream
 
2821
 
 
2822
    def __iter__(self):
 
2823
        if self.randomised:
 
2824
            return iter(self._tests)
 
2825
        self.randomised = True
 
2826
        self.stream.writeln("Randomizing test order using seed %s\n" %
 
2827
            (self.actual_seed()))
 
2828
        # Initialise the random number generator.
 
2829
        random.seed(self.actual_seed())
 
2830
        suite = randomize_suite(self)
 
2831
        del self._tests[:]
 
2832
        self.addTests(suite)
 
2833
        return iter(self._tests)
 
2834
 
 
2835
    def actual_seed(self):
 
2836
        if self.random_seed == "now":
 
2837
            # We convert the seed to a long to make it reuseable across
 
2838
            # invocations (because the user can reenter it).
 
2839
            self.random_seed = long(time.time())
2655
2840
        else:
2656
2841
            # Convert the seed to a long if we can
2657
2842
            try:
2658
 
                random_seed = long(random_seed)
 
2843
                self.random_seed = long(self.random_seed)
2659
2844
            except:
2660
2845
                pass
2661
 
        runner.stream.writeln("Randomizing test order using seed %s\n" %
2662
 
            (random_seed))
2663
 
        random.seed(random_seed)
2664
 
    # Customise the list of tests if requested
2665
 
    if exclude_pattern is not None:
2666
 
        suite = exclude_tests_by_re(suite, exclude_pattern)
2667
 
    if random_order:
2668
 
        order_changer = randomize_suite
2669
 
    else:
2670
 
        order_changer = preserve_input
2671
 
    if pattern != '.*' or random_order:
2672
 
        if matching_tests_first:
2673
 
            suites = map(order_changer, split_suite_by_re(suite, pattern))
2674
 
            suite = TestUtil.TestSuite(suites)
2675
 
        else:
2676
 
            suite = order_changer(filter_suite_by_re(suite, pattern))
2677
 
 
2678
 
    result = runner.run(suite)
2679
 
 
2680
 
    if strict:
2681
 
        return result.wasStrictlySuccessful()
2682
 
 
2683
 
    return result.wasSuccessful()
 
2846
        return self.random_seed
 
2847
 
 
2848
 
 
2849
class TestFirstDecorator(TestDecorator):
 
2850
    """A decorator which moves named tests to the front."""
 
2851
 
 
2852
    def __init__(self, suite, pattern):
 
2853
        TestDecorator.__init__(self, suite)
 
2854
        self.pattern = pattern
 
2855
        self.filtered = False
 
2856
 
 
2857
    def __iter__(self):
 
2858
        if self.filtered:
 
2859
            return iter(self._tests)
 
2860
        self.filtered = True
 
2861
        suites = split_suite_by_re(self, self.pattern)
 
2862
        del self._tests[:]
 
2863
        self.addTests(suites)
 
2864
        return iter(self._tests)
 
2865
 
 
2866
 
 
2867
def partition_tests(suite, count):
 
2868
    """Partition suite into count lists of tests."""
 
2869
    result = []
 
2870
    tests = list(iter_suite_tests(suite))
 
2871
    tests_per_process = int(math.ceil(float(len(tests)) / count))
 
2872
    for block in range(count):
 
2873
        low_test = block * tests_per_process
 
2874
        high_test = low_test + tests_per_process
 
2875
        process_tests = tests[low_test:high_test]
 
2876
        result.append(process_tests)
 
2877
    return result
 
2878
 
 
2879
 
 
2880
def fork_for_tests(suite):
 
2881
    """Take suite and start up one runner per CPU by forking()
 
2882
 
 
2883
    :return: An iterable of TestCase-like objects which can each have
 
2884
        run(result) called on them to feed tests to result, and
 
2885
        cleanup() called on them to stop them/kill children/end threads.
 
2886
    """
 
2887
    concurrency = local_concurrency()
 
2888
    result = []
 
2889
    from subunit import TestProtocolClient, ProtocolTestCase
 
2890
    class TestInOtherProcess(ProtocolTestCase):
 
2891
        # Should be in subunit, I think. RBC.
 
2892
        def __init__(self, stream, pid):
 
2893
            ProtocolTestCase.__init__(self, stream)
 
2894
            self.pid = pid
 
2895
 
 
2896
        def run(self, result):
 
2897
            try:
 
2898
                ProtocolTestCase.run(self, result)
 
2899
            finally:
 
2900
                os.waitpid(self.pid, os.WNOHANG)
 
2901
            # print "pid %d finished" % finished_process
 
2902
 
 
2903
    test_blocks = partition_tests(suite, concurrency)
 
2904
    for process_tests in test_blocks:
 
2905
        process_suite = TestSuite()
 
2906
        process_suite.addTests(process_tests)
 
2907
        c2pread, c2pwrite = os.pipe()
 
2908
        pid = os.fork()
 
2909
        if pid == 0:
 
2910
            try:
 
2911
                os.close(c2pread)
 
2912
                # Leave stderr and stdout open so we can see test noise
 
2913
                # Close stdin so that the child goes away if it decides to
 
2914
                # read from stdin (otherwise its a roulette to see what
 
2915
                # child actually gets keystrokes for pdb etc.
 
2916
                sys.stdin.close()
 
2917
                sys.stdin = None
 
2918
                stream = os.fdopen(c2pwrite, 'wb', 0)
 
2919
                subunit_result = TestProtocolClient(stream)
 
2920
                process_suite.run(subunit_result)
 
2921
            finally:
 
2922
                os._exit(0)
 
2923
        else:
 
2924
            os.close(c2pwrite)
 
2925
            stream = os.fdopen(c2pread, 'rb', 1)
 
2926
            test = TestInOtherProcess(stream, pid)
 
2927
            result.append(test)
 
2928
    return result
 
2929
 
 
2930
 
 
2931
def reinvoke_for_tests(suite):
 
2932
    """Take suite and start up one runner per CPU using subprocess().
 
2933
 
 
2934
    :return: An iterable of TestCase-like objects which can each have
 
2935
        run(result) called on them to feed tests to result, and
 
2936
        cleanup() called on them to stop them/kill children/end threads.
 
2937
    """
 
2938
    concurrency = local_concurrency()
 
2939
    result = []
 
2940
    from subunit import TestProtocolClient, ProtocolTestCase
 
2941
    class TestInSubprocess(ProtocolTestCase):
 
2942
        def __init__(self, process, name):
 
2943
            ProtocolTestCase.__init__(self, process.stdout)
 
2944
            self.process = process
 
2945
            self.process.stdin.close()
 
2946
            self.name = name
 
2947
 
 
2948
        def run(self, result):
 
2949
            try:
 
2950
                ProtocolTestCase.run(self, result)
 
2951
            finally:
 
2952
                self.process.wait()
 
2953
                os.unlink(self.name)
 
2954
            # print "pid %d finished" % finished_process
 
2955
    test_blocks = partition_tests(suite, concurrency)
 
2956
    for process_tests in test_blocks:
 
2957
        # ugly; currently reimplement rather than reuses TestCase methods.
 
2958
        bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
 
2959
        if not os.path.isfile(bzr_path):
 
2960
            # We are probably installed. Assume sys.argv is the right file
 
2961
            bzr_path = sys.argv[0]
 
2962
        fd, test_list_file_name = tempfile.mkstemp()
 
2963
        test_list_file = os.fdopen(fd, 'wb', 1)
 
2964
        for test in process_tests:
 
2965
            test_list_file.write(test.id() + '\n')
 
2966
        test_list_file.close()
 
2967
        try:
 
2968
            argv = [bzr_path, 'selftest', '--load-list', test_list_file_name,
 
2969
                '--subunit']
 
2970
            if '--no-plugins' in sys.argv:
 
2971
                argv.append('--no-plugins')
 
2972
            # stderr=STDOUT would be ideal, but until we prevent noise on
 
2973
            # stderr it can interrupt the subunit protocol.
 
2974
            process = Popen(argv, stdin=PIPE, stdout=PIPE, stderr=PIPE,
 
2975
                bufsize=1)
 
2976
            test = TestInSubprocess(process, test_list_file_name)
 
2977
            result.append(test)
 
2978
        except:
 
2979
            os.unlink(test_list_file_name)
 
2980
            raise
 
2981
    return result
 
2982
 
 
2983
 
 
2984
def cpucount(content):
 
2985
    lines = content.splitlines()
 
2986
    prefix = 'processor'
 
2987
    for line in lines:
 
2988
        if line.startswith(prefix):
 
2989
            concurrency = int(line[line.find(':')+1:]) + 1
 
2990
    return concurrency
 
2991
 
 
2992
 
 
2993
def local_concurrency():
 
2994
    try:
 
2995
        content = file('/proc/cpuinfo', 'rb').read()
 
2996
        concurrency = cpucount(content)
 
2997
    except Exception, e:
 
2998
        concurrency = 1
 
2999
    return concurrency
 
3000
 
 
3001
 
 
3002
class BZRTransformingResult(unittest.TestResult):
 
3003
 
 
3004
    def __init__(self, target):
 
3005
        unittest.TestResult.__init__(self)
 
3006
        self.result = target
 
3007
 
 
3008
    def startTest(self, test):
 
3009
        self.result.startTest(test)
 
3010
 
 
3011
    def stopTest(self, test):
 
3012
        self.result.stopTest(test)
 
3013
 
 
3014
    def addError(self, test, err):
 
3015
        feature = self._error_looks_like('UnavailableFeature: ', err)
 
3016
        if feature is not None:
 
3017
            self.result.addNotSupported(test, feature)
 
3018
        else:
 
3019
            self.result.addError(test, err)
 
3020
 
 
3021
    def addFailure(self, test, err):
 
3022
        known = self._error_looks_like('KnownFailure: ', err)
 
3023
        if known is not None:
 
3024
            self.result._addKnownFailure(test, [KnownFailure,
 
3025
                                                KnownFailure(known), None])
 
3026
        else:
 
3027
            self.result.addFailure(test, err)
 
3028
 
 
3029
    def addSkip(self, test, reason):
 
3030
        self.result.addSkip(test, reason)
 
3031
 
 
3032
    def addSuccess(self, test):
 
3033
        self.result.addSuccess(test)
 
3034
 
 
3035
    def _error_looks_like(self, prefix, err):
 
3036
        """Deserialize exception and returns the stringify value."""
 
3037
        import subunit
 
3038
        value = None
 
3039
        typ, exc, _ = err
 
3040
        if isinstance(exc, subunit.RemoteException):
 
3041
            # stringify the exception gives access to the remote traceback
 
3042
            # We search the last line for 'prefix'
 
3043
            lines = str(exc).split('\n')
 
3044
            if len(lines) > 1:
 
3045
                last = lines[-2] # -1 is empty, final \n
 
3046
            else:
 
3047
                last = lines[-1]
 
3048
            if last.startswith(prefix):
 
3049
                value = last[len(prefix):]
 
3050
        return value
2684
3051
 
2685
3052
 
2686
3053
# Controlled by "bzr selftest -E=..." option
2701
3068
             debug_flags=None,
2702
3069
             starting_with=None,
2703
3070
             runner_class=None,
 
3071
             suite_decorators=None,
2704
3072
             ):
2705
3073
    """Run the whole test suite under the enhanced runner"""
2706
3074
    # XXX: Very ugly way to do this...
2738
3106
                     exclude_pattern=exclude_pattern,
2739
3107
                     strict=strict,
2740
3108
                     runner_class=runner_class,
 
3109
                     suite_decorators=suite_decorators,
2741
3110
                     )
2742
3111
    finally:
2743
3112
        default_transport = old_transport
3014
3383
                   'bzrlib.tests.test_reconfigure',
3015
3384
                   'bzrlib.tests.test_registry',
3016
3385
                   'bzrlib.tests.test_remote',
 
3386
                   'bzrlib.tests.test_rename_map',
3017
3387
                   'bzrlib.tests.test_repository',
3018
3388
                   'bzrlib.tests.test_revert',
3019
3389
                   'bzrlib.tests.test_revision',