834
853
ui.ui_factory = ui.SilentUIFactory()
835
854
self.addCleanup(_restore)
856
def _check_locks(self):
857
"""Check that all lock take/release actions have been paired."""
858
# once we have fixed all the current lock problems, we can change the
859
# following code to always check for mismatched locks, but only do
860
# traceback showing with -Dlock (self._lock_check_thorough is True).
861
# For now, because the test suite will fail, we only assert that lock
862
# matching has occured with -Dlock.
864
acquired_locks = [lock for action, lock in self._lock_actions
865
if action == 'acquired']
866
released_locks = [lock for action, lock in self._lock_actions
867
if action == 'released']
868
broken_locks = [lock for action, lock in self._lock_actions
869
if action == 'broken']
870
# trivially, given the tests for lock acquistion and release, if we
871
# have as many in each list, it should be ok. Some lock tests also
872
# break some locks on purpose and should be taken into account by
873
# considering that breaking a lock is just a dirty way of releasing it.
874
if len(acquired_locks) != (len(released_locks) + len(broken_locks)):
875
message = ('Different number of acquired and '
876
'released or broken locks. (%s, %s + %s)' %
877
(acquired_locks, released_locks, broken_locks))
878
if not self._lock_check_thorough:
879
# Rather than fail, just warn
880
print "Broken test %s: %s" % (self, message)
884
def _track_locks(self):
885
"""Track lock activity during tests."""
886
self._lock_actions = []
887
self._lock_check_thorough = 'lock' not in debug.debug_flags
888
self.addCleanup(self._check_locks)
889
_mod_lock.Lock.hooks.install_named_hook('lock_acquired',
890
self._lock_acquired, None)
891
_mod_lock.Lock.hooks.install_named_hook('lock_released',
892
self._lock_released, None)
893
_mod_lock.Lock.hooks.install_named_hook('lock_broken',
894
self._lock_broken, None)
896
def _lock_acquired(self, result):
897
self._lock_actions.append(('acquired', result))
899
def _lock_released(self, result):
900
self._lock_actions.append(('released', result))
902
def _lock_broken(self, result):
903
self._lock_actions.append(('broken', result))
837
905
def _ndiff_strings(self, a, b):
838
906
"""Return ndiff between two strings containing lines.
2613
2716
if runner_class is None:
2614
2717
runner_class = TextTestRunner
2615
runner = runner_class(stream=sys.stdout,
2720
runner = runner_class(stream=stream,
2616
2721
descriptions=0,
2617
2722
verbosity=verbosity,
2618
2723
bench_history=bench_history,
2619
2724
list_only=list_only,
2621
2727
runner.stop_on_failure=stop_on_failure
2622
# Initialise the random number generator and display the seed used.
2623
# We convert the seed to a long to make it reuseable across invocations.
2624
random_order = False
2625
if random_seed is not None:
2627
if random_seed == "now":
2628
random_seed = long(time.time())
2728
# built in decorator factories:
2730
random_order(random_seed, runner),
2731
exclude_tests(exclude_pattern),
2733
if matching_tests_first:
2734
decorators.append(tests_first(pattern))
2736
decorators.append(filter_tests(pattern))
2737
if suite_decorators:
2738
decorators.extend(suite_decorators)
2739
for decorator in decorators:
2740
suite = decorator(suite)
2741
result = runner.run(suite)
2746
return result.wasStrictlySuccessful()
2748
return result.wasSuccessful()
2751
# A registry where get() returns a suite decorator.
2752
parallel_registry = registry.Registry()
2755
def fork_decorator(suite):
2756
concurrency = local_concurrency()
2757
if concurrency == 1:
2759
from testtools import ConcurrentTestSuite
2760
return ConcurrentTestSuite(suite, fork_for_tests)
2761
parallel_registry.register('fork', fork_decorator)
2764
def subprocess_decorator(suite):
2765
concurrency = local_concurrency()
2766
if concurrency == 1:
2768
from testtools import ConcurrentTestSuite
2769
return ConcurrentTestSuite(suite, reinvoke_for_tests)
2770
parallel_registry.register('subprocess', subprocess_decorator)
2773
def exclude_tests(exclude_pattern):
2774
"""Return a test suite decorator that excludes tests."""
2775
if exclude_pattern is None:
2776
return identity_decorator
2777
def decorator(suite):
2778
return ExcludeDecorator(suite, exclude_pattern)
2782
def filter_tests(pattern):
2784
return identity_decorator
2785
def decorator(suite):
2786
return FilterTestsDecorator(suite, pattern)
2790
def random_order(random_seed, runner):
2791
"""Return a test suite decorator factory for randomising tests order.
2793
:param random_seed: now, a string which casts to a long, or a long.
2794
:param runner: A test runner with a stream attribute to report on.
2796
if random_seed is None:
2797
return identity_decorator
2798
def decorator(suite):
2799
return RandomDecorator(suite, random_seed, runner.stream)
2803
def tests_first(pattern):
2805
return identity_decorator
2806
def decorator(suite):
2807
return TestFirstDecorator(suite, pattern)
2811
def identity_decorator(suite):
2816
class TestDecorator(TestSuite):
2817
"""A decorator for TestCase/TestSuite objects.
2819
Usually, subclasses should override __iter__(used when flattening test
2820
suites), which we do to filter, reorder, parallelise and so on, run() and
2824
def __init__(self, suite):
2825
TestSuite.__init__(self)
2828
def countTestCases(self):
2831
cases += test.countTestCases()
2838
def run(self, result):
2839
# Use iteration on self, not self._tests, to allow subclasses to hook
2842
if result.shouldStop:
2848
class ExcludeDecorator(TestDecorator):
2849
"""A decorator which excludes test matching an exclude pattern."""
2851
def __init__(self, suite, exclude_pattern):
2852
TestDecorator.__init__(self, suite)
2853
self.exclude_pattern = exclude_pattern
2854
self.excluded = False
2858
return iter(self._tests)
2859
self.excluded = True
2860
suite = exclude_tests_by_re(self, self.exclude_pattern)
2862
self.addTests(suite)
2863
return iter(self._tests)
2866
class FilterTestsDecorator(TestDecorator):
2867
"""A decorator which filters tests to those matching a pattern."""
2869
def __init__(self, suite, pattern):
2870
TestDecorator.__init__(self, suite)
2871
self.pattern = pattern
2872
self.filtered = False
2876
return iter(self._tests)
2877
self.filtered = True
2878
suite = filter_suite_by_re(self, self.pattern)
2880
self.addTests(suite)
2881
return iter(self._tests)
2884
class RandomDecorator(TestDecorator):
2885
"""A decorator which randomises the order of its tests."""
2887
def __init__(self, suite, random_seed, stream):
2888
TestDecorator.__init__(self, suite)
2889
self.random_seed = random_seed
2890
self.randomised = False
2891
self.stream = stream
2895
return iter(self._tests)
2896
self.randomised = True
2897
self.stream.writeln("Randomizing test order using seed %s\n" %
2898
(self.actual_seed()))
2899
# Initialise the random number generator.
2900
random.seed(self.actual_seed())
2901
suite = randomize_suite(self)
2903
self.addTests(suite)
2904
return iter(self._tests)
2906
def actual_seed(self):
2907
if self.random_seed == "now":
2908
# We convert the seed to a long to make it reuseable across
2909
# invocations (because the user can reenter it).
2910
self.random_seed = long(time.time())
2630
2912
# Convert the seed to a long if we can
2632
random_seed = long(random_seed)
2914
self.random_seed = long(self.random_seed)
2635
runner.stream.writeln("Randomizing test order using seed %s\n" %
2637
random.seed(random_seed)
2638
# Customise the list of tests if requested
2639
if exclude_pattern is not None:
2640
suite = exclude_tests_by_re(suite, exclude_pattern)
2642
order_changer = randomize_suite
2644
order_changer = preserve_input
2645
if pattern != '.*' or random_order:
2646
if matching_tests_first:
2647
suites = map(order_changer, split_suite_by_re(suite, pattern))
2648
suite = TestUtil.TestSuite(suites)
2650
suite = order_changer(filter_suite_by_re(suite, pattern))
2652
result = runner.run(suite)
2655
return result.wasStrictlySuccessful()
2657
return result.wasSuccessful()
2917
return self.random_seed
2920
class TestFirstDecorator(TestDecorator):
2921
"""A decorator which moves named tests to the front."""
2923
def __init__(self, suite, pattern):
2924
TestDecorator.__init__(self, suite)
2925
self.pattern = pattern
2926
self.filtered = False
2930
return iter(self._tests)
2931
self.filtered = True
2932
suites = split_suite_by_re(self, self.pattern)
2934
self.addTests(suites)
2935
return iter(self._tests)
2938
def partition_tests(suite, count):
2939
"""Partition suite into count lists of tests."""
2941
tests = list(iter_suite_tests(suite))
2942
tests_per_process = int(math.ceil(float(len(tests)) / count))
2943
for block in range(count):
2944
low_test = block * tests_per_process
2945
high_test = low_test + tests_per_process
2946
process_tests = tests[low_test:high_test]
2947
result.append(process_tests)
2951
def fork_for_tests(suite):
2952
"""Take suite and start up one runner per CPU by forking()
2954
:return: An iterable of TestCase-like objects which can each have
2955
run(result) called on them to feed tests to result.
2957
concurrency = local_concurrency()
2959
from subunit import TestProtocolClient, ProtocolTestCase
2960
class TestInOtherProcess(ProtocolTestCase):
2961
# Should be in subunit, I think. RBC.
2962
def __init__(self, stream, pid):
2963
ProtocolTestCase.__init__(self, stream)
2966
def run(self, result):
2968
ProtocolTestCase.run(self, result)
2970
os.waitpid(self.pid, os.WNOHANG)
2972
test_blocks = partition_tests(suite, concurrency)
2973
for process_tests in test_blocks:
2974
process_suite = TestSuite()
2975
process_suite.addTests(process_tests)
2976
c2pread, c2pwrite = os.pipe()
2981
# Leave stderr and stdout open so we can see test noise
2982
# Close stdin so that the child goes away if it decides to
2983
# read from stdin (otherwise its a roulette to see what
2984
# child actually gets keystrokes for pdb etc).
2987
stream = os.fdopen(c2pwrite, 'wb', 1)
2988
subunit_result = TestProtocolClient(stream)
2989
process_suite.run(subunit_result)
2994
stream = os.fdopen(c2pread, 'rb', 1)
2995
test = TestInOtherProcess(stream, pid)
3000
def reinvoke_for_tests(suite):
3001
"""Take suite and start up one runner per CPU using subprocess().
3003
:return: An iterable of TestCase-like objects which can each have
3004
run(result) called on them to feed tests to result.
3006
concurrency = local_concurrency()
3008
from subunit import TestProtocolClient, ProtocolTestCase
3009
class TestInSubprocess(ProtocolTestCase):
3010
def __init__(self, process, name):
3011
ProtocolTestCase.__init__(self, process.stdout)
3012
self.process = process
3013
self.process.stdin.close()
3016
def run(self, result):
3018
ProtocolTestCase.run(self, result)
3021
os.unlink(self.name)
3022
# print "pid %d finished" % finished_process
3023
test_blocks = partition_tests(suite, concurrency)
3024
for process_tests in test_blocks:
3025
# ugly; currently reimplement rather than reuses TestCase methods.
3026
bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
3027
if not os.path.isfile(bzr_path):
3028
# We are probably installed. Assume sys.argv is the right file
3029
bzr_path = sys.argv[0]
3030
fd, test_list_file_name = tempfile.mkstemp()
3031
test_list_file = os.fdopen(fd, 'wb', 1)
3032
for test in process_tests:
3033
test_list_file.write(test.id() + '\n')
3034
test_list_file.close()
3036
argv = [bzr_path, 'selftest', '--load-list', test_list_file_name,
3038
if '--no-plugins' in sys.argv:
3039
argv.append('--no-plugins')
3040
# stderr=STDOUT would be ideal, but until we prevent noise on
3041
# stderr it can interrupt the subunit protocol.
3042
process = Popen(argv, stdin=PIPE, stdout=PIPE, stderr=PIPE,
3044
test = TestInSubprocess(process, test_list_file_name)
3047
os.unlink(test_list_file_name)
3052
def cpucount(content):
3053
lines = content.splitlines()
3054
prefix = 'processor'
3056
if line.startswith(prefix):
3057
concurrency = int(line[line.find(':')+1:]) + 1
3061
def local_concurrency():
3063
content = file('/proc/cpuinfo', 'rb').read()
3064
concurrency = cpucount(content)
3065
except Exception, e:
3070
class BZRTransformingResult(unittest.TestResult):
3072
def __init__(self, target):
3073
unittest.TestResult.__init__(self)
3074
self.result = target
3076
def startTest(self, test):
3077
self.result.startTest(test)
3079
def stopTest(self, test):
3080
self.result.stopTest(test)
3082
def addError(self, test, err):
3083
feature = self._error_looks_like('UnavailableFeature: ', err)
3084
if feature is not None:
3085
self.result.addNotSupported(test, feature)
3087
self.result.addError(test, err)
3089
def addFailure(self, test, err):
3090
known = self._error_looks_like('KnownFailure: ', err)
3091
if known is not None:
3092
self.result._addKnownFailure(test, [KnownFailure,
3093
KnownFailure(known), None])
3095
self.result.addFailure(test, err)
3097
def addSkip(self, test, reason):
3098
self.result.addSkip(test, reason)
3100
def addSuccess(self, test):
3101
self.result.addSuccess(test)
3103
def _error_looks_like(self, prefix, err):
3104
"""Deserialize exception and returns the stringify value."""
3108
if isinstance(exc, subunit.RemoteException):
3109
# stringify the exception gives access to the remote traceback
3110
# We search the last line for 'prefix'
3111
lines = str(exc).split('\n')
3112
while lines and not lines[-1]:
3115
if lines[-1].startswith(prefix):
3116
value = lines[-1][len(prefix):]
2660
3120
# Controlled by "bzr selftest -E=..." option