~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Andrew Bennetts
  • Date: 2009-07-27 05:35:00 UTC
  • mfrom: (4570 +trunk)
  • mto: (4634.6.29 2.0)
  • mto: This revision was merged to the branch mainline in revision 4680.
  • Revision ID: andrew.bennetts@canonical.com-20090727053500-q76zsn2dx33jhmj5
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
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
53
54
    bzrdir,
54
55
    debug,
55
56
    errors,
 
57
    hooks,
 
58
    lock as _mod_lock,
56
59
    memorytree,
57
60
    osutils,
58
61
    progress,
76
79
from bzrlib.merge import merge_inner
77
80
import bzrlib.merge3
78
81
import bzrlib.plugin
79
 
from bzrlib.smart import client, server
 
82
from bzrlib.smart import client, request, server
80
83
import bzrlib.store
81
84
from bzrlib import symbol_versioning
82
85
from bzrlib.symbol_versioning import (
99
102
                          TestLoader,
100
103
                          )
101
104
from bzrlib.tests.treeshape import build_tree_contents
 
105
from bzrlib.ui.text import TextUIFactory
102
106
import bzrlib.version_info_formats.format_custom
103
107
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
104
108
 
131
135
    def __init__(self, stream, descriptions, verbosity,
132
136
                 bench_history=None,
133
137
                 num_tests=None,
 
138
                 strict=False,
134
139
                 ):
135
140
        """Construct new TestResult.
136
141
 
163
168
        self.unsupported = {}
164
169
        self.count = 0
165
170
        self._overall_start_time = time.time()
 
171
        self._strict = strict
 
172
 
 
173
    def done(self):
 
174
        if self._strict:
 
175
            ok = self.wasStrictlySuccessful()
 
176
        else:
 
177
            ok = self.wasSuccessful()
 
178
        if ok:
 
179
            self.stream.write('tests passed\n')
 
180
        else:
 
181
            self.stream.write('tests failed\n')
 
182
        if TestCase._first_thread_leaker_id:
 
183
            self.stream.write(
 
184
                '%s is leaking threads among %d leaking tests.\n' % (
 
185
                TestCase._first_thread_leaker_id,
 
186
                TestCase._leaking_threads_tests))
166
187
 
167
188
    def _extractBenchmarkTime(self, testCase):
168
189
        """Add a benchmark time for the current test case."""
175
196
    def _testTimeString(self, testCase):
176
197
        benchmark_time = self._extractBenchmarkTime(testCase)
177
198
        if benchmark_time is not None:
178
 
            return "%s/%s" % (
179
 
                self._formatTime(benchmark_time),
180
 
                self._elapsedTestTimeString())
 
199
            return self._formatTime(benchmark_time) + "*"
181
200
        else:
182
 
            return "           %s" % self._elapsedTestTimeString()
 
201
            return self._elapsedTestTimeString()
183
202
 
184
203
    def _formatTime(self, seconds):
185
204
        """Format seconds as milliseconds with leading spaces."""
194
213
 
195
214
    def startTest(self, test):
196
215
        unittest.TestResult.startTest(self, test)
 
216
        if self.count == 0:
 
217
            self.startTests()
197
218
        self.report_test_start(test)
198
219
        test.number = self.count
199
220
        self._recordTestStartTime()
200
221
 
 
222
    def startTests(self):
 
223
        self.stream.write(
 
224
            'testing: %s\n' % (osutils.realpath(sys.argv[0]),))
 
225
        self.stream.write(
 
226
            '   %s (%s python%s)\n' % (
 
227
                    bzrlib.__path__[0],
 
228
                    bzrlib.version_string,
 
229
                    bzrlib._format_version_tuple(sys.version_info),
 
230
                    ))
 
231
        self.stream.write('\n')
 
232
 
201
233
    def _recordTestStartTime(self):
202
234
        """Record that a test has started."""
203
235
        self._start_time = time.time()
313
345
            self.stream.write("%s: " % flavour)
314
346
            self.stream.writeln(self.getDescription(test))
315
347
            if getattr(test, '_get_log', None) is not None:
316
 
                self.stream.write('\n')
317
 
                self.stream.write(
318
 
                        ('vvvv[log from %s]' % test.id()).ljust(78,'-'))
319
 
                self.stream.write('\n')
320
 
                self.stream.write(test._get_log())
321
 
                self.stream.write('\n')
322
 
                self.stream.write(
323
 
                        ('^^^^[log from %s]' % test.id()).ljust(78,'-'))
324
 
                self.stream.write('\n')
 
348
                log_contents = test._get_log()
 
349
                if log_contents:
 
350
                    self.stream.write('\n')
 
351
                    self.stream.write(
 
352
                            ('vvvv[log from %s]' % test.id()).ljust(78,'-'))
 
353
                    self.stream.write('\n')
 
354
                    self.stream.write(log_contents)
 
355
                    self.stream.write('\n')
 
356
                    self.stream.write(
 
357
                            ('^^^^[log from %s]' % test.id()).ljust(78,'-'))
 
358
                    self.stream.write('\n')
325
359
            self.stream.writeln(self.separator2)
326
360
            self.stream.writeln("%s" % err)
327
361
 
347
381
                 bench_history=None,
348
382
                 num_tests=None,
349
383
                 pb=None,
 
384
                 strict=None,
350
385
                 ):
351
386
        ExtendedTestResult.__init__(self, stream, descriptions, verbosity,
352
 
            bench_history, num_tests)
 
387
            bench_history, num_tests, strict)
353
388
        if pb is None:
354
389
            self.pb = self.ui.nested_progress_bar()
355
390
            self._supplied_pb = False
363
398
        self.pb.show_bar = False
364
399
 
365
400
    def report_starting(self):
366
 
        self.pb.update('[test 0/%d] starting...' % (self.num_tests))
 
401
        self.pb.update('[test 0/%d] Starting' % (self.num_tests))
367
402
 
368
403
    def _progress_prefix_text(self):
369
404
        # the longer this text, the less space we have to show the test
428
463
        """test cannot be run because feature is missing."""
429
464
 
430
465
    def report_cleaning_up(self):
431
 
        self.pb.update('cleaning up...')
 
466
        self.pb.update('Cleaning up')
432
467
 
433
468
    def finished(self):
434
469
        if not self._supplied_pb:
452
487
    def report_test_start(self, test):
453
488
        self.count += 1
454
489
        name = self._shortened_test_description(test)
455
 
        # width needs space for 6 char status, plus 1 for slash, plus 2 10-char
456
 
        # numbers, plus a trailing blank
 
490
        # width needs space for 6 char status, plus 1 for slash, plus an
 
491
        # 11-char time string, plus a trailing blank
457
492
        # when NUMBERED_DIRS: plus 5 chars on test number, plus 1 char on space
458
493
        self.stream.write(self._ellipsize_to_right(name,
459
 
                          osutils.terminal_width()-30))
 
494
                          osutils.terminal_width()-18))
460
495
        self.stream.flush()
461
496
 
462
497
    def _error_summary(self, err):
510
545
                 descriptions=0,
511
546
                 verbosity=1,
512
547
                 bench_history=None,
513
 
                 list_only=False
 
548
                 list_only=False,
 
549
                 strict=False,
514
550
                 ):
515
551
        self.stream = unittest._WritelnDecorator(stream)
516
552
        self.descriptions = descriptions
517
553
        self.verbosity = verbosity
518
554
        self._bench_history = bench_history
519
555
        self.list_only = list_only
 
556
        self._strict = strict
520
557
 
521
558
    def run(self, test):
522
559
        "Run the given test case or test suite."
530
567
                              self.verbosity,
531
568
                              bench_history=self._bench_history,
532
569
                              num_tests=test.countTestCases(),
 
570
                              strict=self._strict,
533
571
                              )
534
572
        result.stop_early = self.stop_on_failure
535
573
        result.report_starting()
540
578
            for t in iter_suite_tests(test):
541
579
                self.stream.writeln("%s" % (t.id()))
542
580
                run += 1
543
 
            actionTaken = "Listed"
 
581
            return None
544
582
        else:
545
 
            test.run(result)
 
583
            try:
 
584
                import testtools
 
585
            except ImportError:
 
586
                test.run(result)
 
587
            else:
 
588
                if isinstance(test, testtools.ConcurrentTestSuite):
 
589
                    # We need to catch bzr specific behaviors
 
590
                    test.run(BZRTransformingResult(result))
 
591
                else:
 
592
                    test.run(result)
546
593
            run = result.testsRun
547
594
            actionTaken = "Ran"
548
595
        stopTime = time.time()
585
632
 
586
633
def iter_suite_tests(suite):
587
634
    """Return all tests in a suite, recursing through nested suites"""
588
 
    for item in suite._tests:
589
 
        if isinstance(item, unittest.TestCase):
590
 
            yield item
591
 
        elif isinstance(item, unittest.TestSuite):
 
635
    if isinstance(suite, unittest.TestCase):
 
636
        yield suite
 
637
    elif isinstance(suite, unittest.TestSuite):
 
638
        for item in suite:
592
639
            for r in iter_suite_tests(item):
593
640
                yield r
594
 
        else:
595
 
            raise Exception('unknown object %r inside test suite %r'
596
 
                            % (item, suite))
 
641
    else:
 
642
        raise Exception('unknown type %r for object %r'
 
643
                        % (type(suite), suite))
597
644
 
598
645
 
599
646
class TestSkipped(Exception):
656
703
            return setattr(self._cstring, name, val)
657
704
 
658
705
 
659
 
class TestUIFactory(ui.CLIUIFactory):
 
706
class TestUIFactory(TextUIFactory):
660
707
    """A UI Factory for testing.
661
708
 
662
709
    Hide the progress bar but emit note()s.
664
711
    Allows get_password to be tested without real tty attached.
665
712
    """
666
713
 
667
 
    def __init__(self,
668
 
                 stdout=None,
669
 
                 stderr=None,
670
 
                 stdin=None):
671
 
        super(TestUIFactory, self).__init__()
 
714
    def __init__(self, stdout=None, stderr=None, stdin=None):
672
715
        if stdin is not None:
673
716
            # We use a StringIOWrapper to be able to test various
674
717
            # encodings, but the user is still responsible to
675
718
            # encode the string and to set the encoding attribute
676
719
            # of StringIOWrapper.
677
 
            self.stdin = StringIOWrapper(stdin)
678
 
        if stdout is None:
679
 
            self.stdout = sys.stdout
680
 
        else:
681
 
            self.stdout = stdout
682
 
        if stderr is None:
683
 
            self.stderr = sys.stderr
684
 
        else:
685
 
            self.stderr = stderr
 
720
            stdin = StringIOWrapper(stdin)
 
721
        super(TestUIFactory, self).__init__(stdin, stdout, stderr)
686
722
 
687
723
    def clear(self):
688
724
        """See progress.ProgressBar.clear()."""
690
726
    def clear_term(self):
691
727
        """See progress.ProgressBar.clear_term()."""
692
728
 
693
 
    def clear_term(self):
694
 
        """See progress.ProgressBar.clear_term()."""
695
 
 
696
729
    def finished(self):
697
730
        """See progress.ProgressBar.finished()."""
698
731
 
699
 
    def note(self, fmt_string, *args, **kwargs):
 
732
    def note(self, fmt_string, *args):
700
733
        """See progress.ProgressBar.note()."""
701
 
        self.stdout.write((fmt_string + "\n") % args)
 
734
        if args:
 
735
            fmt_string = fmt_string % args
 
736
        self.stdout.write(fmt_string + "\n")
702
737
 
703
738
    def progress_bar(self):
704
739
        return self
709
744
    def update(self, message, count=None, total=None):
710
745
        """See progress.ProgressBar.update()."""
711
746
 
712
 
    def get_non_echoed_password(self, prompt):
 
747
    def get_non_echoed_password(self):
713
748
        """Get password from stdin without trying to handle the echo mode"""
714
 
        if prompt:
715
 
            self.stdout.write(prompt.encode(self.stdout.encoding, 'replace'))
716
749
        password = self.stdin.readline()
717
750
        if not password:
718
751
            raise EOFError
721
754
        return password
722
755
 
723
756
 
724
 
def _report_leaked_threads():
725
 
    bzrlib.trace.warning('%s is leaking threads among %d leaking tests',
726
 
                         TestCase._first_thread_leaker_id,
727
 
                         TestCase._leaking_threads_tests)
728
 
 
729
 
 
730
757
class TestCase(unittest.TestCase):
731
758
    """Base class for bzr unit tests.
732
759
 
758
785
    _gather_lsprof_in_benchmarks = False
759
786
    attrs_to_keep = ('id', '_testMethodName', '_testMethodDoc',
760
787
                     '_log_contents', '_log_file_name', '_benchtime',
761
 
                     '_TestCase__testMethodName')
 
788
                     '_TestCase__testMethodName', '_TestCase__testMethodDoc',)
762
789
 
763
790
    def __init__(self, methodName='testMethod'):
764
791
        super(TestCase, self).__init__(methodName)
765
792
        self._cleanups = []
 
793
        self._bzr_test_setUp_run = False
 
794
        self._bzr_test_tearDown_run = False
766
795
 
767
796
    def setUp(self):
768
797
        unittest.TestCase.setUp(self)
 
798
        self._bzr_test_setUp_run = True
769
799
        self._cleanEnvironment()
770
800
        self._silenceUI()
771
801
        self._startLogFile()
772
802
        self._benchcalls = []
773
803
        self._benchtime = None
774
804
        self._clear_hooks()
 
805
        # Track locks - needs to be called before _clear_debug_flags.
 
806
        self._track_locks()
775
807
        self._clear_debug_flags()
776
808
        TestCase._active_threads = threading.activeCount()
777
809
        self.addCleanup(self._check_leaked_threads)
778
810
 
779
 
    def exc_info(self):
780
 
        absent_attr = object()
781
 
        exc_info = getattr(self, '_exc_info', absent_attr)
782
 
        if exc_info is absent_attr:
783
 
            exc_info = getattr(self, '_TestCase__exc_info')
784
 
        return exc_info()
 
811
    def debug(self):
 
812
        # debug a frame up.
 
813
        import pdb
 
814
        pdb.Pdb().set_trace(sys._getframe().f_back)
785
815
 
786
816
    def _check_leaked_threads(self):
787
817
        active = threading.activeCount()
791
821
            TestCase._leaking_threads_tests += 1
792
822
            if TestCase._first_thread_leaker_id is None:
793
823
                TestCase._first_thread_leaker_id = self.id()
794
 
                # we're not specifically told when all tests are finished.
795
 
                # This will do. We use a function to avoid keeping a reference
796
 
                # to a TestCase object.
797
 
                atexit.register(_report_leaked_threads)
798
824
 
799
825
    def _clear_debug_flags(self):
800
826
        """Prevent externally set debug flags affecting tests.
809
835
 
810
836
    def _clear_hooks(self):
811
837
        # prevent hooks affecting tests
812
 
        import bzrlib.branch
813
 
        import bzrlib.smart.client
814
 
        import bzrlib.smart.server
815
 
        self._preserved_hooks = {
816
 
            bzrlib.branch.Branch: bzrlib.branch.Branch.hooks,
817
 
            bzrlib.mutabletree.MutableTree: bzrlib.mutabletree.MutableTree.hooks,
818
 
            bzrlib.smart.client._SmartClient: bzrlib.smart.client._SmartClient.hooks,
819
 
            bzrlib.smart.server.SmartTCPServer: bzrlib.smart.server.SmartTCPServer.hooks,
820
 
            bzrlib.commands.Command: bzrlib.commands.Command.hooks,
821
 
            }
 
838
        self._preserved_hooks = {}
 
839
        for key, factory in hooks.known_hooks.items():
 
840
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
 
841
            current_hooks = hooks.known_hooks_key_to_object(key)
 
842
            self._preserved_hooks[parent] = (name, current_hooks)
822
843
        self.addCleanup(self._restoreHooks)
823
 
        # reset all hooks to an empty instance of the appropriate type
824
 
        bzrlib.branch.Branch.hooks = bzrlib.branch.BranchHooks()
825
 
        bzrlib.smart.client._SmartClient.hooks = bzrlib.smart.client.SmartClientHooks()
826
 
        bzrlib.smart.server.SmartTCPServer.hooks = bzrlib.smart.server.SmartServerHooks()
827
 
        bzrlib.commands.Command.hooks = bzrlib.commands.CommandHooks()
 
844
        for key, factory in hooks.known_hooks.items():
 
845
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
 
846
            setattr(parent, name, factory())
 
847
        # this hook should always be installed
 
848
        request._install_hook()
828
849
 
829
850
    def _silenceUI(self):
830
851
        """Turn off UI for duration of test"""
835
856
        ui.ui_factory = ui.SilentUIFactory()
836
857
        self.addCleanup(_restore)
837
858
 
 
859
    def _check_locks(self):
 
860
        """Check that all lock take/release actions have been paired."""
 
861
        # once we have fixed all the current lock problems, we can change the
 
862
        # following code to always check for mismatched locks, but only do
 
863
        # traceback showing with -Dlock (self._lock_check_thorough is True).
 
864
        # For now, because the test suite will fail, we only assert that lock
 
865
        # matching has occured with -Dlock.
 
866
        # unhook:
 
867
        acquired_locks = [lock for action, lock in self._lock_actions
 
868
                          if action == 'acquired']
 
869
        released_locks = [lock for action, lock in self._lock_actions
 
870
                          if action == 'released']
 
871
        broken_locks = [lock for action, lock in self._lock_actions
 
872
                        if action == 'broken']
 
873
        # trivially, given the tests for lock acquistion and release, if we
 
874
        # have as many in each list, it should be ok. Some lock tests also
 
875
        # break some locks on purpose and should be taken into account by
 
876
        # considering that breaking a lock is just a dirty way of releasing it.
 
877
        if len(acquired_locks) != (len(released_locks) + len(broken_locks)):
 
878
            message = ('Different number of acquired and '
 
879
                       'released or broken locks. (%s, %s + %s)' %
 
880
                       (acquired_locks, released_locks, broken_locks))
 
881
            if not self._lock_check_thorough:
 
882
                # Rather than fail, just warn
 
883
                print "Broken test %s: %s" % (self, message)
 
884
                return
 
885
            self.fail(message)
 
886
 
 
887
    def _track_locks(self):
 
888
        """Track lock activity during tests."""
 
889
        self._lock_actions = []
 
890
        self._lock_check_thorough = 'lock' not in debug.debug_flags
 
891
        self.addCleanup(self._check_locks)
 
892
        _mod_lock.Lock.hooks.install_named_hook('lock_acquired',
 
893
                                                self._lock_acquired, None)
 
894
        _mod_lock.Lock.hooks.install_named_hook('lock_released',
 
895
                                                self._lock_released, None)
 
896
        _mod_lock.Lock.hooks.install_named_hook('lock_broken',
 
897
                                                self._lock_broken, None)
 
898
 
 
899
    def _lock_acquired(self, result):
 
900
        self._lock_actions.append(('acquired', result))
 
901
 
 
902
    def _lock_released(self, result):
 
903
        self._lock_actions.append(('released', result))
 
904
 
 
905
    def _lock_broken(self, result):
 
906
        self._lock_actions.append(('broken', result))
 
907
 
838
908
    def _ndiff_strings(self, a, b):
839
909
        """Return ndiff between two strings containing lines.
840
910
 
903
973
        self.assertEqual(expected.st_ino, actual.st_ino)
904
974
        self.assertEqual(expected.st_mode, actual.st_mode)
905
975
 
 
976
    def assertLength(self, length, obj_with_len):
 
977
        """Assert that obj_with_len is of length length."""
 
978
        if len(obj_with_len) != length:
 
979
            self.fail("Incorrect length: wanted %d, got %d for %r" % (
 
980
                length, len(obj_with_len), obj_with_len))
 
981
 
906
982
    def assertPositive(self, val):
907
983
        """Assert that val is greater than 0."""
908
984
        self.assertTrue(val > 0, 'expected a positive value, but got %s' % val)
1000
1076
                raise AssertionError("%r is %r." % (left, right))
1001
1077
 
1002
1078
    def assertTransportMode(self, transport, path, mode):
1003
 
        """Fail if a path does not have mode mode.
 
1079
        """Fail if a path does not have mode "mode".
1004
1080
 
1005
1081
        If modes are not supported on this transport, the assertion is ignored.
1006
1082
        """
1009
1085
        path_stat = transport.stat(path)
1010
1086
        actual_mode = stat.S_IMODE(path_stat.st_mode)
1011
1087
        self.assertEqual(mode, actual_mode,
1012
 
            'mode of %r incorrect (%o != %o)' % (path, mode, actual_mode))
 
1088
                         'mode of %r incorrect (%s != %s)'
 
1089
                         % (path, oct(mode), oct(actual_mode)))
1013
1090
 
1014
1091
    def assertIsSameRealPath(self, path1, path2):
1015
1092
        """Fail if path1 and path2 points to different files"""
1017
1094
                         osutils.realpath(path2),
1018
1095
                         "apparent paths:\na = %s\nb = %s\n," % (path1, path2))
1019
1096
 
1020
 
    def assertIsInstance(self, obj, kls):
1021
 
        """Fail if obj is not an instance of kls"""
 
1097
    def assertIsInstance(self, obj, kls, msg=None):
 
1098
        """Fail if obj is not an instance of kls
 
1099
        
 
1100
        :param msg: Supplementary message to show if the assertion fails.
 
1101
        """
1022
1102
        if not isinstance(obj, kls):
1023
 
            self.fail("%r is an instance of %s rather than %s" % (
1024
 
                obj, obj.__class__, kls))
 
1103
            m = "%r is an instance of %s rather than %s" % (
 
1104
                obj, obj.__class__, kls)
 
1105
            if msg:
 
1106
                m += ": " + msg
 
1107
            self.fail(m)
1025
1108
 
1026
1109
    def expectFailure(self, reason, assertion, *args, **kwargs):
1027
1110
        """Invoke a test, expecting it to fail for the given reason.
1241
1324
            # bzr now uses the Win32 API and doesn't rely on APPDATA, but the
1242
1325
            # tests do check our impls match APPDATA
1243
1326
            'BZR_EDITOR': None, # test_msgeditor manipulates this variable
 
1327
            'VISUAL': None,
 
1328
            'EDITOR': None,
1244
1329
            'BZR_EMAIL': None,
1245
1330
            'BZREMAIL': None, # may still be present in the environment
1246
1331
            'EMAIL': None,
1247
1332
            'BZR_PROGRESS_BAR': None,
1248
1333
            'BZR_LOG': None,
1249
1334
            'BZR_PLUGIN_PATH': None,
 
1335
            # Make sure that any text ui tests are consistent regardless of
 
1336
            # the environment the test case is run in; you may want tests that
 
1337
            # test other combinations.  'dumb' is a reasonable guess for tests
 
1338
            # going to a pipe or a StringIO.
 
1339
            'TERM': 'dumb',
 
1340
            'LINES': '25',
 
1341
            'COLUMNS': '80',
1250
1342
            # SSH Agent
1251
1343
            'SSH_AUTH_SOCK': None,
1252
1344
            # Proxies
1258
1350
            'NO_PROXY': None,
1259
1351
            'all_proxy': None,
1260
1352
            'ALL_PROXY': None,
1261
 
            # Nobody cares about these ones AFAIK. So far at
 
1353
            # Nobody cares about ftp_proxy, FTP_PROXY AFAIK. So far at
1262
1354
            # least. If you do (care), please update this comment
1263
 
            # -- vila 20061212
 
1355
            # -- vila 20080401
1264
1356
            'ftp_proxy': None,
1265
1357
            'FTP_PROXY': None,
1266
1358
            'BZR_REMOTE_PATH': None,
1283
1375
            osutils.set_or_unset_env(name, value)
1284
1376
 
1285
1377
    def _restoreHooks(self):
1286
 
        for klass, hooks in self._preserved_hooks.items():
1287
 
            setattr(klass, 'hooks', hooks)
 
1378
        for klass, (name, hooks) in self._preserved_hooks.items():
 
1379
            setattr(klass, name, hooks)
1288
1380
 
1289
1381
    def knownFailure(self, reason):
1290
1382
        """This test has failed for some known reason."""
1293
1385
    def _do_skip(self, result, reason):
1294
1386
        addSkip = getattr(result, 'addSkip', None)
1295
1387
        if not callable(addSkip):
1296
 
            result.addError(self, self.exc_info())
 
1388
            result.addError(self, sys.exc_info())
1297
1389
        else:
1298
1390
            addSkip(self, reason)
1299
1391
 
1307
1399
                else:
1308
1400
                    result.addSuccess(self)
1309
1401
                result.stopTest(self)
1310
 
                return
 
1402
                return result
1311
1403
        try:
1312
1404
            try:
1313
1405
                result.startTest(self)
1321
1413
                try:
1322
1414
                    try:
1323
1415
                        self.setUp()
 
1416
                        if not self._bzr_test_setUp_run:
 
1417
                            self.fail(
 
1418
                                "test setUp did not invoke "
 
1419
                                "bzrlib.tests.TestCase's setUp")
1324
1420
                    except KeyboardInterrupt:
 
1421
                        self._runCleanups()
1325
1422
                        raise
1326
1423
                    except TestSkipped, e:
1327
1424
                        self._do_skip(result, e.args[0])
1328
1425
                        self.tearDown()
1329
 
                        return
 
1426
                        return result
1330
1427
                    except:
1331
 
                        result.addError(self, self.exc_info())
1332
 
                        return
 
1428
                        result.addError(self, sys.exc_info())
 
1429
                        self._runCleanups()
 
1430
                        return result
1333
1431
 
1334
1432
                    ok = False
1335
1433
                    try:
1336
1434
                        testMethod()
1337
1435
                        ok = True
1338
1436
                    except self.failureException:
1339
 
                        result.addFailure(self, self.exc_info())
 
1437
                        result.addFailure(self, sys.exc_info())
1340
1438
                    except TestSkipped, e:
1341
1439
                        if not e.args:
1342
1440
                            reason = "No reason given."
1344
1442
                            reason = e.args[0]
1345
1443
                        self._do_skip(result, reason)
1346
1444
                    except KeyboardInterrupt:
 
1445
                        self._runCleanups()
1347
1446
                        raise
1348
1447
                    except:
1349
 
                        result.addError(self, self.exc_info())
 
1448
                        result.addError(self, sys.exc_info())
1350
1449
 
1351
1450
                    try:
1352
1451
                        self.tearDown()
 
1452
                        if not self._bzr_test_tearDown_run:
 
1453
                            self.fail(
 
1454
                                "test tearDown did not invoke "
 
1455
                                "bzrlib.tests.TestCase's tearDown")
1353
1456
                    except KeyboardInterrupt:
 
1457
                        self._runCleanups()
1354
1458
                        raise
1355
1459
                    except:
1356
 
                        result.addError(self, self.exc_info())
 
1460
                        result.addError(self, sys.exc_info())
 
1461
                        self._runCleanups()
1357
1462
                        ok = False
1358
1463
                    if ok: result.addSuccess(self)
1359
1464
                finally:
1360
1465
                    result.stopTest(self)
1361
 
                return
 
1466
                return result
1362
1467
            except TestNotApplicable:
1363
1468
                # Not moved from the result [yet].
 
1469
                self._runCleanups()
1364
1470
                raise
1365
1471
            except KeyboardInterrupt:
 
1472
                self._runCleanups()
1366
1473
                raise
1367
1474
        finally:
1368
1475
            saved_attrs = {}
1369
 
            absent_attr = object()
1370
1476
            for attr_name in self.attrs_to_keep:
1371
 
                attr = getattr(self, attr_name, absent_attr)
1372
 
                if attr is not absent_attr:
1373
 
                    saved_attrs[attr_name] = attr
 
1477
                if attr_name in self.__dict__:
 
1478
                    saved_attrs[attr_name] = self.__dict__[attr_name]
1374
1479
            self.__dict__ = saved_attrs
1375
1480
 
1376
1481
    def tearDown(self):
1377
1482
        self._runCleanups()
1378
1483
        self._log_contents = ''
 
1484
        self._bzr_test_tearDown_run = True
1379
1485
        unittest.TestCase.tearDown(self)
1380
1486
 
1381
1487
    def time(self, callable, *args, **kwargs):
1558
1664
            stdin=stdin,
1559
1665
            working_dir=working_dir,
1560
1666
            )
 
1667
        self.assertIsInstance(error_regexes, (list, tuple))
1561
1668
        for regex in error_regexes:
1562
1669
            self.assertContainsRe(err, regex)
1563
1670
        return out, err
2108
2215
        made_control = self.make_bzrdir(relpath, format=format)
2109
2216
        return made_control.create_repository(shared=shared)
2110
2217
 
 
2218
    def make_smart_server(self, path):
 
2219
        smart_server = server.SmartTCPServer_for_testing()
 
2220
        smart_server.setUp(self.get_server())
 
2221
        remote_transport = get_transport(smart_server.get_url()).clone(path)
 
2222
        self.addCleanup(smart_server.tearDown)
 
2223
        return remote_transport
 
2224
 
2111
2225
    def make_branch_and_memory_tree(self, relpath, format=None):
2112
2226
        """Create a branch on the default transport and a MemoryTree for it."""
2113
2227
        b = self.make_branch(relpath, format=format)
2114
2228
        return memorytree.MemoryTree.create_on_branch(b)
2115
2229
 
2116
2230
    def make_branch_builder(self, relpath, format=None):
2117
 
        return branchbuilder.BranchBuilder(self.get_transport(relpath),
2118
 
            format=format)
 
2231
        branch = self.make_branch(relpath, format=format)
 
2232
        return branchbuilder.BranchBuilder(branch=branch)
2119
2233
 
2120
2234
    def overrideEnvironmentForTesting(self):
2121
2235
        os.environ['HOME'] = self.test_home_dir
2198
2312
        For TestCaseInTempDir we create a temporary directory based on the test
2199
2313
        name and then create two subdirs - test and home under it.
2200
2314
        """
2201
 
        name_prefix = osutils.pathjoin(self.TEST_ROOT, self._getTestDirPrefix())
 
2315
        name_prefix = osutils.pathjoin(TestCaseWithMemoryTransport.TEST_ROOT,
 
2316
            self._getTestDirPrefix())
2202
2317
        name = name_prefix
2203
2318
        for i in range(100):
2204
2319
            if os.path.exists(name):
2222
2337
        self.addCleanup(self.deleteTestDir)
2223
2338
 
2224
2339
    def deleteTestDir(self):
2225
 
        os.chdir(self.TEST_ROOT)
 
2340
        os.chdir(TestCaseWithMemoryTransport.TEST_ROOT)
2226
2341
        _rmtree_temp_dir(self.test_base_dir)
2227
2342
 
2228
2343
    def build_tree(self, shape, line_endings='binary', transport=None):
2407
2522
    :param pattern: A regular expression string.
2408
2523
    :return: A callable that returns True if the re matches.
2409
2524
    """
2410
 
    filter_re = re.compile(pattern)
 
2525
    filter_re = osutils.re_compile_checked(pattern, 0,
 
2526
        'test filter')
2411
2527
    def condition(test):
2412
2528
        test_id = test.id()
2413
2529
        return filter_re.search(test_id)
2598
2714
              random_seed=None,
2599
2715
              exclude_pattern=None,
2600
2716
              strict=False,
2601
 
              runner_class=None):
 
2717
              runner_class=None,
 
2718
              suite_decorators=None,
 
2719
              stream=None):
2602
2720
    """Run a test suite for bzr selftest.
2603
2721
 
2604
2722
    :param runner_class: The class of runner to use. Must support the
2613
2731
        verbosity = 1
2614
2732
    if runner_class is None:
2615
2733
        runner_class = TextTestRunner
2616
 
    runner = runner_class(stream=sys.stdout,
 
2734
    if stream is None:
 
2735
        stream = sys.stdout
 
2736
    runner = runner_class(stream=stream,
2617
2737
                            descriptions=0,
2618
2738
                            verbosity=verbosity,
2619
2739
                            bench_history=bench_history,
2620
2740
                            list_only=list_only,
 
2741
                            strict=strict,
2621
2742
                            )
2622
2743
    runner.stop_on_failure=stop_on_failure
2623
 
    # Initialise the random number generator and display the seed used.
2624
 
    # We convert the seed to a long to make it reuseable across invocations.
2625
 
    random_order = False
2626
 
    if random_seed is not None:
2627
 
        random_order = True
2628
 
        if random_seed == "now":
2629
 
            random_seed = long(time.time())
 
2744
    # built in decorator factories:
 
2745
    decorators = [
 
2746
        random_order(random_seed, runner),
 
2747
        exclude_tests(exclude_pattern),
 
2748
        ]
 
2749
    if matching_tests_first:
 
2750
        decorators.append(tests_first(pattern))
 
2751
    else:
 
2752
        decorators.append(filter_tests(pattern))
 
2753
    if suite_decorators:
 
2754
        decorators.extend(suite_decorators)
 
2755
    for decorator in decorators:
 
2756
        suite = decorator(suite)
 
2757
    result = runner.run(suite)
 
2758
    if list_only:
 
2759
        return True
 
2760
    result.done()
 
2761
    if strict:
 
2762
        return result.wasStrictlySuccessful()
 
2763
    else:
 
2764
        return result.wasSuccessful()
 
2765
 
 
2766
 
 
2767
# A registry where get() returns a suite decorator.
 
2768
parallel_registry = registry.Registry()
 
2769
 
 
2770
 
 
2771
def fork_decorator(suite):
 
2772
    concurrency = osutils.local_concurrency()
 
2773
    if concurrency == 1:
 
2774
        return suite
 
2775
    from testtools import ConcurrentTestSuite
 
2776
    return ConcurrentTestSuite(suite, fork_for_tests)
 
2777
parallel_registry.register('fork', fork_decorator)
 
2778
 
 
2779
 
 
2780
def subprocess_decorator(suite):
 
2781
    concurrency = osutils.local_concurrency()
 
2782
    if concurrency == 1:
 
2783
        return suite
 
2784
    from testtools import ConcurrentTestSuite
 
2785
    return ConcurrentTestSuite(suite, reinvoke_for_tests)
 
2786
parallel_registry.register('subprocess', subprocess_decorator)
 
2787
 
 
2788
 
 
2789
def exclude_tests(exclude_pattern):
 
2790
    """Return a test suite decorator that excludes tests."""
 
2791
    if exclude_pattern is None:
 
2792
        return identity_decorator
 
2793
    def decorator(suite):
 
2794
        return ExcludeDecorator(suite, exclude_pattern)
 
2795
    return decorator
 
2796
 
 
2797
 
 
2798
def filter_tests(pattern):
 
2799
    if pattern == '.*':
 
2800
        return identity_decorator
 
2801
    def decorator(suite):
 
2802
        return FilterTestsDecorator(suite, pattern)
 
2803
    return decorator
 
2804
 
 
2805
 
 
2806
def random_order(random_seed, runner):
 
2807
    """Return a test suite decorator factory for randomising tests order.
 
2808
    
 
2809
    :param random_seed: now, a string which casts to a long, or a long.
 
2810
    :param runner: A test runner with a stream attribute to report on.
 
2811
    """
 
2812
    if random_seed is None:
 
2813
        return identity_decorator
 
2814
    def decorator(suite):
 
2815
        return RandomDecorator(suite, random_seed, runner.stream)
 
2816
    return decorator
 
2817
 
 
2818
 
 
2819
def tests_first(pattern):
 
2820
    if pattern == '.*':
 
2821
        return identity_decorator
 
2822
    def decorator(suite):
 
2823
        return TestFirstDecorator(suite, pattern)
 
2824
    return decorator
 
2825
 
 
2826
 
 
2827
def identity_decorator(suite):
 
2828
    """Return suite."""
 
2829
    return suite
 
2830
 
 
2831
 
 
2832
class TestDecorator(TestSuite):
 
2833
    """A decorator for TestCase/TestSuite objects.
 
2834
    
 
2835
    Usually, subclasses should override __iter__(used when flattening test
 
2836
    suites), which we do to filter, reorder, parallelise and so on, run() and
 
2837
    debug().
 
2838
    """
 
2839
 
 
2840
    def __init__(self, suite):
 
2841
        TestSuite.__init__(self)
 
2842
        self.addTest(suite)
 
2843
 
 
2844
    def countTestCases(self):
 
2845
        cases = 0
 
2846
        for test in self:
 
2847
            cases += test.countTestCases()
 
2848
        return cases
 
2849
 
 
2850
    def debug(self):
 
2851
        for test in self:
 
2852
            test.debug()
 
2853
 
 
2854
    def run(self, result):
 
2855
        # Use iteration on self, not self._tests, to allow subclasses to hook
 
2856
        # into __iter__.
 
2857
        for test in self:
 
2858
            if result.shouldStop:
 
2859
                break
 
2860
            test.run(result)
 
2861
        return result
 
2862
 
 
2863
 
 
2864
class ExcludeDecorator(TestDecorator):
 
2865
    """A decorator which excludes test matching an exclude pattern."""
 
2866
 
 
2867
    def __init__(self, suite, exclude_pattern):
 
2868
        TestDecorator.__init__(self, suite)
 
2869
        self.exclude_pattern = exclude_pattern
 
2870
        self.excluded = False
 
2871
 
 
2872
    def __iter__(self):
 
2873
        if self.excluded:
 
2874
            return iter(self._tests)
 
2875
        self.excluded = True
 
2876
        suite = exclude_tests_by_re(self, self.exclude_pattern)
 
2877
        del self._tests[:]
 
2878
        self.addTests(suite)
 
2879
        return iter(self._tests)
 
2880
 
 
2881
 
 
2882
class FilterTestsDecorator(TestDecorator):
 
2883
    """A decorator which filters tests to those matching a pattern."""
 
2884
 
 
2885
    def __init__(self, suite, pattern):
 
2886
        TestDecorator.__init__(self, suite)
 
2887
        self.pattern = pattern
 
2888
        self.filtered = False
 
2889
 
 
2890
    def __iter__(self):
 
2891
        if self.filtered:
 
2892
            return iter(self._tests)
 
2893
        self.filtered = True
 
2894
        suite = filter_suite_by_re(self, self.pattern)
 
2895
        del self._tests[:]
 
2896
        self.addTests(suite)
 
2897
        return iter(self._tests)
 
2898
 
 
2899
 
 
2900
class RandomDecorator(TestDecorator):
 
2901
    """A decorator which randomises the order of its tests."""
 
2902
 
 
2903
    def __init__(self, suite, random_seed, stream):
 
2904
        TestDecorator.__init__(self, suite)
 
2905
        self.random_seed = random_seed
 
2906
        self.randomised = False
 
2907
        self.stream = stream
 
2908
 
 
2909
    def __iter__(self):
 
2910
        if self.randomised:
 
2911
            return iter(self._tests)
 
2912
        self.randomised = True
 
2913
        self.stream.writeln("Randomizing test order using seed %s\n" %
 
2914
            (self.actual_seed()))
 
2915
        # Initialise the random number generator.
 
2916
        random.seed(self.actual_seed())
 
2917
        suite = randomize_suite(self)
 
2918
        del self._tests[:]
 
2919
        self.addTests(suite)
 
2920
        return iter(self._tests)
 
2921
 
 
2922
    def actual_seed(self):
 
2923
        if self.random_seed == "now":
 
2924
            # We convert the seed to a long to make it reuseable across
 
2925
            # invocations (because the user can reenter it).
 
2926
            self.random_seed = long(time.time())
2630
2927
        else:
2631
2928
            # Convert the seed to a long if we can
2632
2929
            try:
2633
 
                random_seed = long(random_seed)
 
2930
                self.random_seed = long(self.random_seed)
2634
2931
            except:
2635
2932
                pass
2636
 
        runner.stream.writeln("Randomizing test order using seed %s\n" %
2637
 
            (random_seed))
2638
 
        random.seed(random_seed)
2639
 
    # Customise the list of tests if requested
2640
 
    if exclude_pattern is not None:
2641
 
        suite = exclude_tests_by_re(suite, exclude_pattern)
2642
 
    if random_order:
2643
 
        order_changer = randomize_suite
2644
 
    else:
2645
 
        order_changer = preserve_input
2646
 
    if pattern != '.*' or random_order:
2647
 
        if matching_tests_first:
2648
 
            suites = map(order_changer, split_suite_by_re(suite, pattern))
2649
 
            suite = TestUtil.TestSuite(suites)
2650
 
        else:
2651
 
            suite = order_changer(filter_suite_by_re(suite, pattern))
2652
 
 
2653
 
    result = runner.run(suite)
2654
 
 
2655
 
    if strict:
2656
 
        return result.wasStrictlySuccessful()
2657
 
 
2658
 
    return result.wasSuccessful()
 
2933
        return self.random_seed
 
2934
 
 
2935
 
 
2936
class TestFirstDecorator(TestDecorator):
 
2937
    """A decorator which moves named tests to the front."""
 
2938
 
 
2939
    def __init__(self, suite, pattern):
 
2940
        TestDecorator.__init__(self, suite)
 
2941
        self.pattern = pattern
 
2942
        self.filtered = False
 
2943
 
 
2944
    def __iter__(self):
 
2945
        if self.filtered:
 
2946
            return iter(self._tests)
 
2947
        self.filtered = True
 
2948
        suites = split_suite_by_re(self, self.pattern)
 
2949
        del self._tests[:]
 
2950
        self.addTests(suites)
 
2951
        return iter(self._tests)
 
2952
 
 
2953
 
 
2954
def partition_tests(suite, count):
 
2955
    """Partition suite into count lists of tests."""
 
2956
    result = []
 
2957
    tests = list(iter_suite_tests(suite))
 
2958
    tests_per_process = int(math.ceil(float(len(tests)) / count))
 
2959
    for block in range(count):
 
2960
        low_test = block * tests_per_process
 
2961
        high_test = low_test + tests_per_process
 
2962
        process_tests = tests[low_test:high_test]
 
2963
        result.append(process_tests)
 
2964
    return result
 
2965
 
 
2966
 
 
2967
def fork_for_tests(suite):
 
2968
    """Take suite and start up one runner per CPU by forking()
 
2969
 
 
2970
    :return: An iterable of TestCase-like objects which can each have
 
2971
        run(result) called on them to feed tests to result.
 
2972
    """
 
2973
    concurrency = osutils.local_concurrency()
 
2974
    result = []
 
2975
    from subunit import TestProtocolClient, ProtocolTestCase
 
2976
    try:
 
2977
        from subunit.test_results import AutoTimingTestResultDecorator
 
2978
    except ImportError:
 
2979
        AutoTimingTestResultDecorator = lambda x:x
 
2980
    class TestInOtherProcess(ProtocolTestCase):
 
2981
        # Should be in subunit, I think. RBC.
 
2982
        def __init__(self, stream, pid):
 
2983
            ProtocolTestCase.__init__(self, stream)
 
2984
            self.pid = pid
 
2985
 
 
2986
        def run(self, result):
 
2987
            try:
 
2988
                ProtocolTestCase.run(self, result)
 
2989
            finally:
 
2990
                os.waitpid(self.pid, os.WNOHANG)
 
2991
 
 
2992
    test_blocks = partition_tests(suite, concurrency)
 
2993
    for process_tests in test_blocks:
 
2994
        process_suite = TestSuite()
 
2995
        process_suite.addTests(process_tests)
 
2996
        c2pread, c2pwrite = os.pipe()
 
2997
        pid = os.fork()
 
2998
        if pid == 0:
 
2999
            try:
 
3000
                os.close(c2pread)
 
3001
                # Leave stderr and stdout open so we can see test noise
 
3002
                # Close stdin so that the child goes away if it decides to
 
3003
                # read from stdin (otherwise its a roulette to see what
 
3004
                # child actually gets keystrokes for pdb etc).
 
3005
                sys.stdin.close()
 
3006
                sys.stdin = None
 
3007
                stream = os.fdopen(c2pwrite, 'wb', 1)
 
3008
                subunit_result = AutoTimingTestResultDecorator(
 
3009
                    TestProtocolClient(stream))
 
3010
                process_suite.run(subunit_result)
 
3011
            finally:
 
3012
                os._exit(0)
 
3013
        else:
 
3014
            os.close(c2pwrite)
 
3015
            stream = os.fdopen(c2pread, 'rb', 1)
 
3016
            test = TestInOtherProcess(stream, pid)
 
3017
            result.append(test)
 
3018
    return result
 
3019
 
 
3020
 
 
3021
def reinvoke_for_tests(suite):
 
3022
    """Take suite and start up one runner per CPU using subprocess().
 
3023
 
 
3024
    :return: An iterable of TestCase-like objects which can each have
 
3025
        run(result) called on them to feed tests to result.
 
3026
    """
 
3027
    concurrency = osutils.local_concurrency()
 
3028
    result = []
 
3029
    from subunit import ProtocolTestCase
 
3030
    class TestInSubprocess(ProtocolTestCase):
 
3031
        def __init__(self, process, name):
 
3032
            ProtocolTestCase.__init__(self, process.stdout)
 
3033
            self.process = process
 
3034
            self.process.stdin.close()
 
3035
            self.name = name
 
3036
 
 
3037
        def run(self, result):
 
3038
            try:
 
3039
                ProtocolTestCase.run(self, result)
 
3040
            finally:
 
3041
                self.process.wait()
 
3042
                os.unlink(self.name)
 
3043
            # print "pid %d finished" % finished_process
 
3044
    test_blocks = partition_tests(suite, concurrency)
 
3045
    for process_tests in test_blocks:
 
3046
        # ugly; currently reimplement rather than reuses TestCase methods.
 
3047
        bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
 
3048
        if not os.path.isfile(bzr_path):
 
3049
            # We are probably installed. Assume sys.argv is the right file
 
3050
            bzr_path = sys.argv[0]
 
3051
        fd, test_list_file_name = tempfile.mkstemp()
 
3052
        test_list_file = os.fdopen(fd, 'wb', 1)
 
3053
        for test in process_tests:
 
3054
            test_list_file.write(test.id() + '\n')
 
3055
        test_list_file.close()
 
3056
        try:
 
3057
            argv = [bzr_path, 'selftest', '--load-list', test_list_file_name,
 
3058
                '--subunit']
 
3059
            if '--no-plugins' in sys.argv:
 
3060
                argv.append('--no-plugins')
 
3061
            # stderr=STDOUT would be ideal, but until we prevent noise on
 
3062
            # stderr it can interrupt the subunit protocol.
 
3063
            process = Popen(argv, stdin=PIPE, stdout=PIPE, stderr=PIPE,
 
3064
                bufsize=1)
 
3065
            test = TestInSubprocess(process, test_list_file_name)
 
3066
            result.append(test)
 
3067
        except:
 
3068
            os.unlink(test_list_file_name)
 
3069
            raise
 
3070
    return result
 
3071
 
 
3072
 
 
3073
class BZRTransformingResult(unittest.TestResult):
 
3074
 
 
3075
    def __init__(self, target):
 
3076
        unittest.TestResult.__init__(self)
 
3077
        self.result = target
 
3078
 
 
3079
    def startTest(self, test):
 
3080
        self.result.startTest(test)
 
3081
 
 
3082
    def stopTest(self, test):
 
3083
        self.result.stopTest(test)
 
3084
 
 
3085
    def addError(self, test, err):
 
3086
        feature = self._error_looks_like('UnavailableFeature: ', err)
 
3087
        if feature is not None:
 
3088
            self.result.addNotSupported(test, feature)
 
3089
        else:
 
3090
            self.result.addError(test, err)
 
3091
 
 
3092
    def addFailure(self, test, err):
 
3093
        known = self._error_looks_like('KnownFailure: ', err)
 
3094
        if known is not None:
 
3095
            self.result._addKnownFailure(test, [KnownFailure,
 
3096
                                                KnownFailure(known), None])
 
3097
        else:
 
3098
            self.result.addFailure(test, err)
 
3099
 
 
3100
    def addSkip(self, test, reason):
 
3101
        self.result.addSkip(test, reason)
 
3102
 
 
3103
    def addSuccess(self, test):
 
3104
        self.result.addSuccess(test)
 
3105
 
 
3106
    def _error_looks_like(self, prefix, err):
 
3107
        """Deserialize exception and returns the stringify value."""
 
3108
        import subunit
 
3109
        value = None
 
3110
        typ, exc, _ = err
 
3111
        if isinstance(exc, subunit.RemoteException):
 
3112
            # stringify the exception gives access to the remote traceback
 
3113
            # We search the last line for 'prefix'
 
3114
            lines = str(exc).split('\n')
 
3115
            while lines and not lines[-1]:
 
3116
                lines.pop(-1)
 
3117
            if lines:
 
3118
                if lines[-1].startswith(prefix):
 
3119
                    value = lines[-1][len(prefix):]
 
3120
        return value
2659
3121
 
2660
3122
 
2661
3123
# Controlled by "bzr selftest -E=..." option
2676
3138
             debug_flags=None,
2677
3139
             starting_with=None,
2678
3140
             runner_class=None,
 
3141
             suite_decorators=None,
2679
3142
             ):
2680
3143
    """Run the whole test suite under the enhanced runner"""
2681
3144
    # XXX: Very ugly way to do this...
2713
3176
                     exclude_pattern=exclude_pattern,
2714
3177
                     strict=strict,
2715
3178
                     runner_class=runner_class,
 
3179
                     suite_decorators=suite_decorators,
2716
3180
                     )
2717
3181
    finally:
2718
3182
        default_transport = old_transport
2888
3352
    testmod_names = [
2889
3353
                   'bzrlib.doc',
2890
3354
                   'bzrlib.tests.blackbox',
2891
 
                   'bzrlib.tests.branch_implementations',
2892
 
                   'bzrlib.tests.bzrdir_implementations',
2893
3355
                   'bzrlib.tests.commands',
2894
 
                   'bzrlib.tests.interrepository_implementations',
2895
 
                   'bzrlib.tests.intertree_implementations',
2896
 
                   'bzrlib.tests.inventory_implementations',
 
3356
                   'bzrlib.tests.per_branch',
 
3357
                   'bzrlib.tests.per_bzrdir',
 
3358
                   'bzrlib.tests.per_interrepository',
 
3359
                   'bzrlib.tests.per_intertree',
 
3360
                   'bzrlib.tests.per_inventory',
2897
3361
                   'bzrlib.tests.per_interbranch',
2898
3362
                   'bzrlib.tests.per_lock',
 
3363
                   'bzrlib.tests.per_transport',
 
3364
                   'bzrlib.tests.per_tree',
2899
3365
                   'bzrlib.tests.per_repository',
 
3366
                   'bzrlib.tests.per_repository_chk',
2900
3367
                   'bzrlib.tests.per_repository_reference',
 
3368
                   'bzrlib.tests.per_workingtree',
 
3369
                   'bzrlib.tests.test__annotator',
 
3370
                   'bzrlib.tests.test__chk_map',
2901
3371
                   'bzrlib.tests.test__dirstate_helpers',
 
3372
                   'bzrlib.tests.test__groupcompress',
 
3373
                   'bzrlib.tests.test__known_graph',
 
3374
                   'bzrlib.tests.test__rio',
2902
3375
                   'bzrlib.tests.test__walkdirs_win32',
2903
3376
                   'bzrlib.tests.test_ancestry',
2904
3377
                   'bzrlib.tests.test_annotate',
2905
3378
                   'bzrlib.tests.test_api',
2906
3379
                   'bzrlib.tests.test_atomicfile',
2907
3380
                   'bzrlib.tests.test_bad_files',
 
3381
                   'bzrlib.tests.test_bencode',
2908
3382
                   'bzrlib.tests.test_bisect_multi',
2909
3383
                   'bzrlib.tests.test_branch',
2910
3384
                   'bzrlib.tests.test_branchbuilder',
2912
3386
                   'bzrlib.tests.test_bugtracker',
2913
3387
                   'bzrlib.tests.test_bundle',
2914
3388
                   'bzrlib.tests.test_bzrdir',
 
3389
                   'bzrlib.tests.test__chunks_to_lines',
2915
3390
                   'bzrlib.tests.test_cache_utf8',
 
3391
                   'bzrlib.tests.test_chk_map',
 
3392
                   'bzrlib.tests.test_chk_serializer',
2916
3393
                   'bzrlib.tests.test_chunk_writer',
2917
 
                   'bzrlib.tests.test__chunks_to_lines',
 
3394
                   'bzrlib.tests.test_clean_tree',
2918
3395
                   'bzrlib.tests.test_commands',
2919
3396
                   'bzrlib.tests.test_commit',
2920
3397
                   'bzrlib.tests.test_commit_merge',
2923
3400
                   'bzrlib.tests.test_counted_lock',
2924
3401
                   'bzrlib.tests.test_decorators',
2925
3402
                   'bzrlib.tests.test_delta',
 
3403
                   'bzrlib.tests.test_debug',
2926
3404
                   'bzrlib.tests.test_deprecated_graph',
2927
3405
                   'bzrlib.tests.test_diff',
2928
3406
                   'bzrlib.tests.test_directory_service',
2929
3407
                   'bzrlib.tests.test_dirstate',
2930
3408
                   'bzrlib.tests.test_email_message',
 
3409
                   'bzrlib.tests.test_eol_filters',
2931
3410
                   'bzrlib.tests.test_errors',
2932
3411
                   'bzrlib.tests.test_export',
2933
3412
                   'bzrlib.tests.test_extract',
2934
3413
                   'bzrlib.tests.test_fetch',
2935
3414
                   'bzrlib.tests.test_fifo_cache',
 
3415
                   'bzrlib.tests.test_filters',
2936
3416
                   'bzrlib.tests.test_ftp_transport',
2937
3417
                   'bzrlib.tests.test_foreign',
2938
3418
                   'bzrlib.tests.test_generate_docs',
2940
3420
                   'bzrlib.tests.test_globbing',
2941
3421
                   'bzrlib.tests.test_gpg',
2942
3422
                   'bzrlib.tests.test_graph',
 
3423
                   'bzrlib.tests.test_groupcompress',
2943
3424
                   'bzrlib.tests.test_hashcache',
2944
3425
                   'bzrlib.tests.test_help',
2945
3426
                   'bzrlib.tests.test_hooks',
2946
3427
                   'bzrlib.tests.test_http',
2947
 
                   'bzrlib.tests.test_http_implementations',
2948
3428
                   'bzrlib.tests.test_http_response',
2949
3429
                   'bzrlib.tests.test_https_ca_bundle',
2950
3430
                   'bzrlib.tests.test_identitymap',
2952
3432
                   'bzrlib.tests.test_index',
2953
3433
                   'bzrlib.tests.test_info',
2954
3434
                   'bzrlib.tests.test_inv',
 
3435
                   'bzrlib.tests.test_inventory_delta',
2955
3436
                   'bzrlib.tests.test_knit',
2956
3437
                   'bzrlib.tests.test_lazy_import',
2957
3438
                   'bzrlib.tests.test_lazy_regex',
2986
3467
                   'bzrlib.tests.test_reconfigure',
2987
3468
                   'bzrlib.tests.test_registry',
2988
3469
                   'bzrlib.tests.test_remote',
 
3470
                   'bzrlib.tests.test_rename_map',
2989
3471
                   'bzrlib.tests.test_repository',
2990
3472
                   'bzrlib.tests.test_revert',
2991
3473
                   'bzrlib.tests.test_revision',
2995
3477
                   'bzrlib.tests.test_rules',
2996
3478
                   'bzrlib.tests.test_sampler',
2997
3479
                   'bzrlib.tests.test_selftest',
 
3480
                   'bzrlib.tests.test_serializer',
2998
3481
                   'bzrlib.tests.test_setup',
2999
3482
                   'bzrlib.tests.test_sftp_transport',
3000
3483
                   'bzrlib.tests.test_shelf',
3021
3504
                   'bzrlib.tests.test_transactions',
3022
3505
                   'bzrlib.tests.test_transform',
3023
3506
                   'bzrlib.tests.test_transport',
3024
 
                   'bzrlib.tests.test_transport_implementations',
3025
3507
                   'bzrlib.tests.test_transport_log',
3026
3508
                   'bzrlib.tests.test_tree',
3027
3509
                   'bzrlib.tests.test_treebuilder',
3042
3524
                   'bzrlib.tests.test_workingtree_4',
3043
3525
                   'bzrlib.tests.test_wsgi',
3044
3526
                   'bzrlib.tests.test_xml',
3045
 
                   'bzrlib.tests.tree_implementations',
3046
 
                   'bzrlib.tests.workingtree_implementations',
3047
 
                   'bzrlib.util.tests.test_bencode',
3048
3527
                   ]
3049
3528
 
3050
3529
    loader = TestUtil.TestLoader()
3051
3530
 
 
3531
    if keep_only is not None:
 
3532
        id_filter = TestIdList(keep_only)
3052
3533
    if starting_with:
3053
3534
        starting_with = [test_prefix_alias_registry.resolve_alias(start)
3054
3535
                         for start in starting_with]
3067
3548
        loader = TestUtil.FilteredByModuleTestLoader(interesting_module)
3068
3549
 
3069
3550
    elif keep_only is not None:
3070
 
        id_filter = TestIdList(keep_only)
3071
3551
        loader = TestUtil.FilteredByModuleTestLoader(id_filter.refers_to)
3072
3552
        def interesting_module(name):
3073
3553
            return id_filter.refers_to(name)
3158
3638
    return suite
3159
3639
 
3160
3640
 
3161
 
def multiply_tests_from_modules(module_name_list, scenario_iter, loader=None):
3162
 
    """Adapt all tests in some given modules to given scenarios.
3163
 
 
3164
 
    This is the recommended public interface for test parameterization.
3165
 
    Typically the test_suite() method for a per-implementation test
3166
 
    suite will call multiply_tests_from_modules and return the
3167
 
    result.
3168
 
 
3169
 
    :param module_name_list: List of fully-qualified names of test
3170
 
        modules.
3171
 
    :param scenario_iter: Iterable of pairs of (scenario_name,
3172
 
        scenario_param_dict).
3173
 
    :param loader: If provided, will be used instead of a new
3174
 
        bzrlib.tests.TestLoader() instance.
3175
 
 
3176
 
    This returns a new TestSuite containing the cross product of
3177
 
    all the tests in all the modules, each repeated for each scenario.
3178
 
    Each test is adapted by adding the scenario name at the end
3179
 
    of its name, and updating the test object's __dict__ with the
3180
 
    scenario_param_dict.
3181
 
 
3182
 
    >>> r = multiply_tests_from_modules(
3183
 
    ...     ['bzrlib.tests.test_sampler'],
3184
 
    ...     [('one', dict(param=1)),
3185
 
    ...      ('two', dict(param=2))])
3186
 
    >>> tests = list(iter_suite_tests(r))
3187
 
    >>> len(tests)
3188
 
    2
3189
 
    >>> tests[0].id()
3190
 
    'bzrlib.tests.test_sampler.DemoTest.test_nothing(one)'
3191
 
    >>> tests[0].param
3192
 
    1
3193
 
    >>> tests[1].param
3194
 
    2
3195
 
    """
3196
 
    # XXX: Isn't load_tests() a better way to provide the same functionality
3197
 
    # without forcing a predefined TestScenarioApplier ? --vila 080215
3198
 
    if loader is None:
3199
 
        loader = TestUtil.TestLoader()
3200
 
 
3201
 
    suite = loader.suiteClass()
3202
 
 
3203
 
    adapter = TestScenarioApplier()
3204
 
    adapter.scenarios = list(scenario_iter)
3205
 
    adapt_modules(module_name_list, adapter, loader, suite)
3206
 
    return suite
3207
 
 
3208
 
 
3209
3641
def multiply_scenarios(scenarios_left, scenarios_right):
3210
3642
    """Multiply two sets of scenarios.
3211
3643
 
3220
3652
        for right_name, right_dict in scenarios_right]
3221
3653
 
3222
3654
 
3223
 
 
3224
 
def adapt_modules(mods_list, adapter, loader, suite):
3225
 
    """Adapt the modules in mods_list using adapter and add to suite."""
3226
 
    tests = loader.loadTestsFromModuleNames(mods_list)
3227
 
    adapt_tests(tests, adapter, suite)
3228
 
 
3229
 
 
3230
 
def adapt_tests(tests_list, adapter, suite):
3231
 
    """Adapt the tests in tests_list using adapter and add to suite."""
3232
 
    for test in iter_suite_tests(tests_list):
3233
 
        suite.addTests(adapter.adapt(test))
 
3655
def multiply_tests(tests, scenarios, result):
 
3656
    """Multiply tests_list by scenarios into result.
 
3657
 
 
3658
    This is the core workhorse for test parameterisation.
 
3659
 
 
3660
    Typically the load_tests() method for a per-implementation test suite will
 
3661
    call multiply_tests and return the result.
 
3662
 
 
3663
    :param tests: The tests to parameterise.
 
3664
    :param scenarios: The scenarios to apply: pairs of (scenario_name,
 
3665
        scenario_param_dict).
 
3666
    :param result: A TestSuite to add created tests to.
 
3667
 
 
3668
    This returns the passed in result TestSuite with the cross product of all
 
3669
    the tests repeated once for each scenario.  Each test is adapted by adding
 
3670
    the scenario name at the end of its id(), and updating the test object's
 
3671
    __dict__ with the scenario_param_dict.
 
3672
 
 
3673
    >>> import bzrlib.tests.test_sampler
 
3674
    >>> r = multiply_tests(
 
3675
    ...     bzrlib.tests.test_sampler.DemoTest('test_nothing'),
 
3676
    ...     [('one', dict(param=1)),
 
3677
    ...      ('two', dict(param=2))],
 
3678
    ...     TestSuite())
 
3679
    >>> tests = list(iter_suite_tests(r))
 
3680
    >>> len(tests)
 
3681
    2
 
3682
    >>> tests[0].id()
 
3683
    'bzrlib.tests.test_sampler.DemoTest.test_nothing(one)'
 
3684
    >>> tests[0].param
 
3685
    1
 
3686
    >>> tests[1].param
 
3687
    2
 
3688
    """
 
3689
    for test in iter_suite_tests(tests):
 
3690
        apply_scenarios(test, scenarios, result)
 
3691
    return result
 
3692
 
 
3693
 
 
3694
def apply_scenarios(test, scenarios, result):
 
3695
    """Apply the scenarios in scenarios to test and add to result.
 
3696
 
 
3697
    :param test: The test to apply scenarios to.
 
3698
    :param scenarios: An iterable of scenarios to apply to test.
 
3699
    :return: result
 
3700
    :seealso: apply_scenario
 
3701
    """
 
3702
    for scenario in scenarios:
 
3703
        result.addTest(apply_scenario(test, scenario))
 
3704
    return result
 
3705
 
 
3706
 
 
3707
def apply_scenario(test, scenario):
 
3708
    """Copy test and apply scenario to it.
 
3709
 
 
3710
    :param test: A test to adapt.
 
3711
    :param scenario: A tuple describing the scenarion.
 
3712
        The first element of the tuple is the new test id.
 
3713
        The second element is a dict containing attributes to set on the
 
3714
        test.
 
3715
    :return: The adapted test.
 
3716
    """
 
3717
    new_id = "%s(%s)" % (test.id(), scenario[0])
 
3718
    new_test = clone_test(test, new_id)
 
3719
    for name, value in scenario[1].items():
 
3720
        setattr(new_test, name, value)
 
3721
    return new_test
 
3722
 
 
3723
 
 
3724
def clone_test(test, new_id):
 
3725
    """Clone a test giving it a new id.
 
3726
 
 
3727
    :param test: The test to clone.
 
3728
    :param new_id: The id to assign to it.
 
3729
    :return: The new test.
 
3730
    """
 
3731
    from copy import deepcopy
 
3732
    new_test = deepcopy(test)
 
3733
    new_test.id = lambda: new_id
 
3734
    return new_test
3234
3735
 
3235
3736
 
3236
3737
def _rmtree_temp_dir(dirname):
3249
3750
        osutils.rmtree(dirname)
3250
3751
    except OSError, e:
3251
3752
        if sys.platform == 'win32' and e.errno == errno.EACCES:
3252
 
            sys.stderr.write(('Permission denied: '
3253
 
                                 'unable to remove testing dir '
3254
 
                                 '%s\n' % os.path.basename(dirname)))
 
3753
            sys.stderr.write('Permission denied: '
 
3754
                             'unable to remove testing dir '
 
3755
                             '%s\n%s'
 
3756
                             % (os.path.basename(dirname), e))
3255
3757
        else:
3256
3758
            raise
3257
3759
 
3341
3843
UnicodeFilenameFeature = _UnicodeFilenameFeature()
3342
3844
 
3343
3845
 
3344
 
class TestScenarioApplier(object):
3345
 
    """A tool to apply scenarios to tests."""
3346
 
 
3347
 
    def adapt(self, test):
3348
 
        """Return a TestSuite containing a copy of test for each scenario."""
3349
 
        result = unittest.TestSuite()
3350
 
        for scenario in self.scenarios:
3351
 
            result.addTest(self.adapt_test_to_scenario(test, scenario))
3352
 
        return result
3353
 
 
3354
 
    def adapt_test_to_scenario(self, test, scenario):
3355
 
        """Copy test and apply scenario to it.
3356
 
 
3357
 
        :param test: A test to adapt.
3358
 
        :param scenario: A tuple describing the scenarion.
3359
 
            The first element of the tuple is the new test id.
3360
 
            The second element is a dict containing attributes to set on the
3361
 
            test.
3362
 
        :return: The adapted test.
3363
 
        """
3364
 
        from copy import deepcopy
3365
 
        new_test = deepcopy(test)
3366
 
        for name, value in scenario[1].items():
3367
 
            setattr(new_test, name, value)
3368
 
        new_id = "%s(%s)" % (new_test.id(), scenario[0])
3369
 
        new_test.id = lambda: new_id
3370
 
        return new_test
3371
 
 
3372
 
 
3373
3846
def probe_unicode_in_user_encoding():
3374
3847
    """Try to encode several unicode strings to use in unicode-aware tests.
3375
3848
    Return first successfull match.
3403
3876
    return None
3404
3877
 
3405
3878
 
3406
 
class _FTPServerFeature(Feature):
3407
 
    """Some tests want an FTP Server, check if one is available.
3408
 
 
3409
 
    Right now, the only way this is available is if 'medusa' is installed.
3410
 
    http://www.amk.ca/python/code/medusa.html
3411
 
    """
3412
 
 
3413
 
    def _probe(self):
3414
 
        try:
3415
 
            import bzrlib.tests.ftp_server
3416
 
            return True
3417
 
        except ImportError:
3418
 
            return False
3419
 
 
3420
 
    def feature_name(self):
3421
 
        return 'FTPServer'
3422
 
 
3423
 
 
3424
 
FTPServerFeature = _FTPServerFeature()
3425
 
 
3426
 
 
3427
3879
class _HTTPSServerFeature(Feature):
3428
3880
    """Some tests want an https Server, check if one is available.
3429
3881
 
3529
3981
        return 'case-insensitive filesystem'
3530
3982
 
3531
3983
CaseInsensitiveFilesystemFeature = _CaseInsensitiveFilesystemFeature()
 
3984
 
 
3985
 
 
3986
class _SubUnitFeature(Feature):
 
3987
    """Check if subunit is available."""
 
3988
 
 
3989
    def _probe(self):
 
3990
        try:
 
3991
            import subunit
 
3992
            return True
 
3993
        except ImportError:
 
3994
            return False
 
3995
 
 
3996
    def feature_name(self):
 
3997
        return 'subunit'
 
3998
 
 
3999
SubUnitFeature = _SubUnitFeature()
 
4000
# Only define SubUnitBzrRunner if subunit is available.
 
4001
try:
 
4002
    from subunit import TestProtocolClient
 
4003
    try:
 
4004
        from subunit.test_results import AutoTimingTestResultDecorator
 
4005
    except ImportError:
 
4006
        AutoTimingTestResultDecorator = lambda x:x
 
4007
    class SubUnitBzrRunner(TextTestRunner):
 
4008
        def run(self, test):
 
4009
            result = AutoTimingTestResultDecorator(
 
4010
                TestProtocolClient(self.stream))
 
4011
            test.run(result)
 
4012
            return result
 
4013
except ImportError:
 
4014
    pass