~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Matt Nordhoff
  • Date: 2009-04-04 02:50:01 UTC
  • mfrom: (4253 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4256.
  • Revision ID: mnordhoff@mattnordhoff.com-20090404025001-z1403k0tatmc8l91
Merge bzr.dev, fixing conflicts.

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,
56
58
    memorytree,
57
59
    osutils,
58
60
    progress,
76
78
from bzrlib.merge import merge_inner
77
79
import bzrlib.merge3
78
80
import bzrlib.plugin
79
 
from bzrlib.smart import client, server
 
81
from bzrlib.smart import client, request, server
80
82
import bzrlib.store
81
83
from bzrlib import symbol_versioning
82
84
from bzrlib.symbol_versioning import (
127
129
    """
128
130
 
129
131
    stop_early = False
130
 
    
 
132
 
131
133
    def __init__(self, stream, descriptions, verbosity,
132
134
                 bench_history=None,
133
135
                 num_tests=None,
163
165
        self.unsupported = {}
164
166
        self.count = 0
165
167
        self._overall_start_time = time.time()
166
 
    
 
168
 
167
169
    def _extractBenchmarkTime(self, testCase):
168
170
        """Add a benchmark time for the current test case."""
169
171
        return getattr(testCase, "_benchtime", None)
170
 
    
 
172
 
171
173
    def _elapsedTestTimeString(self):
172
174
        """Return a time string for the overall time the current test has taken."""
173
175
        return self._formatTime(time.time() - self._start_time)
216
218
        fails with an unexpected error.
217
219
        """
218
220
        self._testConcluded(test)
219
 
        if isinstance(err[1], TestSkipped):
220
 
            return self._addSkipped(test, err)
 
221
        if isinstance(err[1], TestNotApplicable):
 
222
            return self._addNotApplicable(test, err)
221
223
        elif isinstance(err[1], UnavailableFeature):
222
224
            return self.addNotSupported(test, err[1].args[0])
223
225
        else:
277
279
        """The test will not be run because of a missing feature.
278
280
        """
279
281
        # this can be called in two different ways: it may be that the
280
 
        # test started running, and then raised (through addError) 
 
282
        # test started running, and then raised (through addError)
281
283
        # UnavailableFeature.  Alternatively this method can be called
282
284
        # while probing for features before running the tests; in that
283
285
        # case we will see startTest and stopTest, but the test will never
286
288
        self.unsupported[str(feature)] += 1
287
289
        self.report_unsupported(test, feature)
288
290
 
289
 
    def _addSkipped(self, test, skip_excinfo):
 
291
    def addSkip(self, test, reason):
 
292
        """A test has not run for 'reason'."""
 
293
        self.skip_count += 1
 
294
        self.report_skip(test, reason)
 
295
 
 
296
    def _addNotApplicable(self, test, skip_excinfo):
290
297
        if isinstance(skip_excinfo[1], TestNotApplicable):
291
298
            self.not_applicable_count += 1
292
299
            self.report_not_applicable(test, skip_excinfo)
293
 
        else:
294
 
            self.skip_count += 1
295
 
            self.report_skip(test, skip_excinfo)
296
300
        try:
297
301
            test.tearDown()
298
302
        except KeyboardInterrupt:
299
303
            raise
300
304
        except:
301
 
            self.addError(test, test._exc_info())
 
305
            self.addError(test, test.exc_info())
302
306
        else:
303
307
            # seems best to treat this as success from point-of-view of unittest
304
308
            # -- it actually does nothing so it barely matters :)
361
365
        self.pb.show_bar = False
362
366
 
363
367
    def report_starting(self):
364
 
        self.pb.update('[test 0/%d] starting...' % (self.num_tests))
 
368
        self.pb.update('[test 0/%d] Starting' % (self.num_tests))
365
369
 
366
370
    def _progress_prefix_text(self):
367
371
        # the longer this text, the less space we have to show the test
394
398
        self.count += 1
395
399
        self.pb.update(
396
400
                self._progress_prefix_text()
397
 
                + ' ' 
 
401
                + ' '
398
402
                + self._shortened_test_description(test))
399
403
 
400
404
    def _test_description(self, test):
401
405
        return self._shortened_test_description(test)
402
406
 
403
407
    def report_error(self, test, err):
404
 
        self.pb.note('ERROR: %s\n    %s\n', 
 
408
        self.pb.note('ERROR: %s\n    %s\n',
405
409
            self._test_description(test),
406
410
            err[1],
407
411
            )
408
412
 
409
413
    def report_failure(self, test, err):
410
 
        self.pb.note('FAIL: %s\n    %s\n', 
 
414
        self.pb.note('FAIL: %s\n    %s\n',
411
415
            self._test_description(test),
412
416
            err[1],
413
417
            )
416
420
        self.pb.note('XFAIL: %s\n%s\n',
417
421
            self._test_description(test), err[1])
418
422
 
419
 
    def report_skip(self, test, skip_excinfo):
 
423
    def report_skip(self, test, reason):
420
424
        pass
421
425
 
422
426
    def report_not_applicable(self, test, skip_excinfo):
424
428
 
425
429
    def report_unsupported(self, test, feature):
426
430
        """test cannot be run because feature is missing."""
427
 
                  
 
431
 
428
432
    def report_cleaning_up(self):
429
 
        self.pb.update('cleaning up...')
 
433
        self.pb.update('Cleaning up')
430
434
 
431
435
    def finished(self):
432
436
        if not self._supplied_pb:
485
489
        # used to show the output in PQM.
486
490
        self.stream.flush()
487
491
 
488
 
    def report_skip(self, test, skip_excinfo):
 
492
    def report_skip(self, test, reason):
489
493
        self.stream.writeln(' SKIP %s\n%s'
490
 
                % (self._testTimeString(test),
491
 
                   self._error_summary(skip_excinfo)))
 
494
                % (self._testTimeString(test), reason))
492
495
 
493
496
    def report_not_applicable(self, test, skip_excinfo):
494
497
        self.stream.writeln('  N/A %s\n%s'
540
543
                self.stream.writeln("%s" % (t.id()))
541
544
                run += 1
542
545
            actionTaken = "Listed"
543
 
        else: 
544
 
            test.run(result)
 
546
        else:
 
547
            try:
 
548
                import testtools
 
549
            except ImportError:
 
550
                test.run(result)
 
551
            else:
 
552
                if isinstance(test, testtools.ConcurrentTestSuite):
 
553
                    # We need to catch bzr specific behaviors
 
554
                    test.run(BZRTransformingResult(result))
 
555
                else:
 
556
                    test.run(result)
545
557
            run = result.testsRun
546
558
            actionTaken = "Ran"
547
559
        stopTime = time.time()
584
596
 
585
597
def iter_suite_tests(suite):
586
598
    """Return all tests in a suite, recursing through nested suites"""
587
 
    for item in suite._tests:
588
 
        if isinstance(item, unittest.TestCase):
589
 
            yield item
590
 
        elif isinstance(item, unittest.TestSuite):
 
599
    if isinstance(suite, unittest.TestCase):
 
600
        yield suite
 
601
    elif isinstance(suite, unittest.TestSuite):
 
602
        for item in suite:
591
603
            for r in iter_suite_tests(item):
592
604
                yield r
593
 
        else:
594
 
            raise Exception('unknown object %r inside test suite %r'
595
 
                            % (item, suite))
 
605
    else:
 
606
        raise Exception('unknown type %r for object %r'
 
607
                        % (type(suite), suite))
596
608
 
597
609
 
598
610
class TestSkipped(Exception):
602
614
class TestNotApplicable(TestSkipped):
603
615
    """A test is not applicable to the situation where it was run.
604
616
 
605
 
    This is only normally raised by parameterized tests, if they find that 
606
 
    the instance they're constructed upon does not support one aspect 
 
617
    This is only normally raised by parameterized tests, if they find that
 
618
    the instance they're constructed upon does not support one aspect
607
619
    of its interface.
608
620
    """
609
621
 
631
643
 
632
644
class StringIOWrapper(object):
633
645
    """A wrapper around cStringIO which just adds an encoding attribute.
634
 
    
 
646
 
635
647
    Internally we can check sys.stdout to see what the output encoding
636
648
    should be. However, cStringIO has no encoding attribute that we can
637
649
    set. So we wrap it instead.
663
675
    Allows get_password to be tested without real tty attached.
664
676
    """
665
677
 
666
 
    def __init__(self,
667
 
                 stdout=None,
668
 
                 stderr=None,
669
 
                 stdin=None):
670
 
        super(TestUIFactory, self).__init__()
 
678
    def __init__(self, stdout=None, stderr=None, stdin=None):
671
679
        if stdin is not None:
672
680
            # We use a StringIOWrapper to be able to test various
673
681
            # encodings, but the user is still responsible to
674
682
            # encode the string and to set the encoding attribute
675
683
            # of StringIOWrapper.
676
 
            self.stdin = StringIOWrapper(stdin)
677
 
        if stdout is None:
678
 
            self.stdout = sys.stdout
679
 
        else:
680
 
            self.stdout = stdout
681
 
        if stderr is None:
682
 
            self.stderr = sys.stderr
683
 
        else:
684
 
            self.stderr = stderr
 
684
            stdin = StringIOWrapper(stdin)
 
685
        super(TestUIFactory, self).__init__(stdin, stdout, stderr)
685
686
 
686
687
    def clear(self):
687
688
        """See progress.ProgressBar.clear()."""
689
690
    def clear_term(self):
690
691
        """See progress.ProgressBar.clear_term()."""
691
692
 
692
 
    def clear_term(self):
693
 
        """See progress.ProgressBar.clear_term()."""
694
 
 
695
693
    def finished(self):
696
694
        """See progress.ProgressBar.finished()."""
697
695
 
708
706
    def update(self, message, count=None, total=None):
709
707
        """See progress.ProgressBar.update()."""
710
708
 
711
 
    def get_non_echoed_password(self, prompt):
 
709
    def get_non_echoed_password(self):
712
710
        """Get password from stdin without trying to handle the echo mode"""
713
 
        if prompt:
714
 
            self.stdout.write(prompt.encode(self.stdout.encoding, 'replace'))
715
711
        password = self.stdin.readline()
716
712
        if not password:
717
713
            raise EOFError
728
724
 
729
725
class TestCase(unittest.TestCase):
730
726
    """Base class for bzr unit tests.
731
 
    
732
 
    Tests that need access to disk resources should subclass 
 
727
 
 
728
    Tests that need access to disk resources should subclass
733
729
    TestCaseInTempDir not TestCase.
734
730
 
735
731
    Error and debug log messages are redirected from their usual
737
733
    retrieved by _get_log().  We use a real OS file, not an in-memory object,
738
734
    so that it can also capture file IO.  When the test completes this file
739
735
    is read into memory and removed from disk.
740
 
       
 
736
 
741
737
    There are also convenience functions to invoke bzr's command-line
742
738
    routine, and to build and check bzr trees.
743
 
   
 
739
 
744
740
    In addition to the usual method of overriding tearDown(), this class also
745
741
    allows subclasses to register functions into the _cleanups list, which is
746
742
    run in order as the object is torn down.  It's less likely this will be
762
758
    def __init__(self, methodName='testMethod'):
763
759
        super(TestCase, self).__init__(methodName)
764
760
        self._cleanups = []
 
761
        self._bzr_test_setUp_run = False
 
762
        self._bzr_test_tearDown_run = False
765
763
 
766
764
    def setUp(self):
767
765
        unittest.TestCase.setUp(self)
 
766
        self._bzr_test_setUp_run = True
768
767
        self._cleanEnvironment()
769
768
        self._silenceUI()
770
769
        self._startLogFile()
775
774
        TestCase._active_threads = threading.activeCount()
776
775
        self.addCleanup(self._check_leaked_threads)
777
776
 
 
777
    def debug(self):
 
778
        # debug a frame up.
 
779
        import pdb
 
780
        pdb.Pdb().set_trace(sys._getframe().f_back)
 
781
 
778
782
    def _check_leaked_threads(self):
779
783
        active = threading.activeCount()
780
784
        leaked_threads = active - TestCase._active_threads
801
805
 
802
806
    def _clear_hooks(self):
803
807
        # prevent hooks affecting tests
804
 
        import bzrlib.branch
805
 
        import bzrlib.smart.client
806
 
        import bzrlib.smart.server
807
 
        self._preserved_hooks = {
808
 
            bzrlib.branch.Branch: bzrlib.branch.Branch.hooks,
809
 
            bzrlib.mutabletree.MutableTree: bzrlib.mutabletree.MutableTree.hooks,
810
 
            bzrlib.smart.client._SmartClient: bzrlib.smart.client._SmartClient.hooks,
811
 
            bzrlib.smart.server.SmartTCPServer: bzrlib.smart.server.SmartTCPServer.hooks,
812
 
            bzrlib.commands.Command: bzrlib.commands.Command.hooks,
813
 
            }
 
808
        self._preserved_hooks = {}
 
809
        for key, factory in hooks.known_hooks.items():
 
810
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
 
811
            current_hooks = hooks.known_hooks_key_to_object(key)
 
812
            self._preserved_hooks[parent] = (name, current_hooks)
814
813
        self.addCleanup(self._restoreHooks)
815
 
        # reset all hooks to an empty instance of the appropriate type
816
 
        bzrlib.branch.Branch.hooks = bzrlib.branch.BranchHooks()
817
 
        bzrlib.smart.client._SmartClient.hooks = bzrlib.smart.client.SmartClientHooks()
818
 
        bzrlib.smart.server.SmartTCPServer.hooks = bzrlib.smart.server.SmartServerHooks()
819
 
        bzrlib.commands.Command.hooks = bzrlib.commands.CommandHooks()
 
814
        for key, factory in hooks.known_hooks.items():
 
815
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
 
816
            setattr(parent, name, factory())
 
817
        # this hook should always be installed
 
818
        request._install_hook()
820
819
 
821
820
    def _silenceUI(self):
822
821
        """Turn off UI for duration of test"""
829
828
 
830
829
    def _ndiff_strings(self, a, b):
831
830
        """Return ndiff between two strings containing lines.
832
 
        
 
831
 
833
832
        A trailing newline is added if missing to make the strings
834
833
        print properly."""
835
834
        if b and b[-1] != '\n':
860
859
 
861
860
    def assertEqualDiff(self, a, b, message=None):
862
861
        """Assert two texts are equal, if not raise an exception.
863
 
        
864
 
        This is intended for use with multi-line strings where it can 
 
862
 
 
863
        This is intended for use with multi-line strings where it can
865
864
        be hard to find the differences by eye.
866
865
        """
867
866
        # TODO: perhaps override assertEquals to call this for strings?
875
874
            message = 'second string is missing a final newline.\n'
876
875
        raise AssertionError(message +
877
876
                             self._ndiff_strings(a, b))
878
 
        
 
877
 
879
878
    def assertEqualMode(self, mode, mode_test):
880
879
        self.assertEqual(mode, mode_test,
881
880
                         'mode mismatch %o != %o' % (mode, mode_test))
895
894
        self.assertEqual(expected.st_ino, actual.st_ino)
896
895
        self.assertEqual(expected.st_mode, actual.st_mode)
897
896
 
 
897
    def assertLength(self, length, obj_with_len):
 
898
        """Assert that obj_with_len is of length length."""
 
899
        if len(obj_with_len) != length:
 
900
            self.fail("Incorrect length: wanted %d, got %d for %r" % (
 
901
                length, len(obj_with_len), obj_with_len))
 
902
 
898
903
    def assertPositive(self, val):
899
904
        """Assert that val is greater than 0."""
900
905
        self.assertTrue(val > 0, 'expected a positive value, but got %s' % val)
939
944
 
940
945
    def assertListRaises(self, excClass, func, *args, **kwargs):
941
946
        """Fail unless excClass is raised when the iterator from func is used.
942
 
        
 
947
 
943
948
        Many functions can return generators this makes sure
944
949
        to wrap them in a list() call to make sure the whole generator
945
950
        is run, and that the proper exception is raised.
993
998
 
994
999
    def assertTransportMode(self, transport, path, mode):
995
1000
        """Fail if a path does not have mode "mode".
996
 
        
 
1001
 
997
1002
        If modes are not supported on this transport, the assertion is ignored.
998
1003
        """
999
1004
        if not transport._can_roundtrip_unix_modebits():
1001
1006
        path_stat = transport.stat(path)
1002
1007
        actual_mode = stat.S_IMODE(path_stat.st_mode)
1003
1008
        self.assertEqual(mode, actual_mode,
1004
 
            'mode of %r incorrect (%o != %o)' % (path, mode, actual_mode))
 
1009
                         'mode of %r incorrect (%s != %s)'
 
1010
                         % (path, oct(mode), oct(actual_mode)))
1005
1011
 
1006
1012
    def assertIsSameRealPath(self, path1, path2):
1007
1013
        """Fail if path1 and path2 points to different files"""
1170
1176
    def callDeprecated(self, expected, callable, *args, **kwargs):
1171
1177
        """Assert that a callable is deprecated in a particular way.
1172
1178
 
1173
 
        This is a very precise test for unusual requirements. The 
 
1179
        This is a very precise test for unusual requirements. The
1174
1180
        applyDeprecated helper function is probably more suited for most tests
1175
1181
        as it allows you to simply specify the deprecation format being used
1176
1182
        and will ensure that that is issued for the function being called.
1221
1227
    def addCleanup(self, callable, *args, **kwargs):
1222
1228
        """Arrange to run a callable when this case is torn down.
1223
1229
 
1224
 
        Callables are run in the reverse of the order they are registered, 
 
1230
        Callables are run in the reverse of the order they are registered,
1225
1231
        ie last-in first-out.
1226
1232
        """
1227
1233
        self._cleanups.append((callable, args, kwargs))
1233
1239
            # bzr now uses the Win32 API and doesn't rely on APPDATA, but the
1234
1240
            # tests do check our impls match APPDATA
1235
1241
            'BZR_EDITOR': None, # test_msgeditor manipulates this variable
 
1242
            'VISUAL': None,
 
1243
            'EDITOR': None,
1236
1244
            'BZR_EMAIL': None,
1237
1245
            'BZREMAIL': None, # may still be present in the environment
1238
1246
            'EMAIL': None,
1250
1258
            'NO_PROXY': None,
1251
1259
            'all_proxy': None,
1252
1260
            'ALL_PROXY': None,
1253
 
            # Nobody cares about these ones AFAIK. So far at
 
1261
            # Nobody cares about ftp_proxy, FTP_PROXY AFAIK. So far at
1254
1262
            # least. If you do (care), please update this comment
1255
 
            # -- vila 20061212
 
1263
            # -- vila 20080401
1256
1264
            'ftp_proxy': None,
1257
1265
            'FTP_PROXY': None,
1258
1266
            'BZR_REMOTE_PATH': None,
1275
1283
            osutils.set_or_unset_env(name, value)
1276
1284
 
1277
1285
    def _restoreHooks(self):
1278
 
        for klass, hooks in self._preserved_hooks.items():
1279
 
            setattr(klass, 'hooks', hooks)
 
1286
        for klass, (name, hooks) in self._preserved_hooks.items():
 
1287
            setattr(klass, name, hooks)
1280
1288
 
1281
1289
    def knownFailure(self, reason):
1282
1290
        """This test has failed for some known reason."""
1283
1291
        raise KnownFailure(reason)
1284
1292
 
 
1293
    def _do_skip(self, result, reason):
 
1294
        addSkip = getattr(result, 'addSkip', None)
 
1295
        if not callable(addSkip):
 
1296
            result.addError(self, sys.exc_info())
 
1297
        else:
 
1298
            addSkip(self, reason)
 
1299
 
1285
1300
    def run(self, result=None):
1286
1301
        if result is None: result = self.defaultTestResult()
1287
1302
        for feature in getattr(self, '_test_needs_features', []):
1294
1309
                result.stopTest(self)
1295
1310
                return
1296
1311
        try:
1297
 
            return unittest.TestCase.run(self, result)
 
1312
            try:
 
1313
                result.startTest(self)
 
1314
                absent_attr = object()
 
1315
                # Python 2.5
 
1316
                method_name = getattr(self, '_testMethodName', absent_attr)
 
1317
                if method_name is absent_attr:
 
1318
                    # Python 2.4
 
1319
                    method_name = getattr(self, '_TestCase__testMethodName')
 
1320
                testMethod = getattr(self, method_name)
 
1321
                try:
 
1322
                    try:
 
1323
                        self.setUp()
 
1324
                        if not self._bzr_test_setUp_run:
 
1325
                            self.fail(
 
1326
                                "test setUp did not invoke "
 
1327
                                "bzrlib.tests.TestCase's setUp")
 
1328
                    except KeyboardInterrupt:
 
1329
                        raise
 
1330
                    except TestSkipped, e:
 
1331
                        self._do_skip(result, e.args[0])
 
1332
                        self.tearDown()
 
1333
                        return
 
1334
                    except:
 
1335
                        result.addError(self, sys.exc_info())
 
1336
                        return
 
1337
 
 
1338
                    ok = False
 
1339
                    try:
 
1340
                        testMethod()
 
1341
                        ok = True
 
1342
                    except self.failureException:
 
1343
                        result.addFailure(self, sys.exc_info())
 
1344
                    except TestSkipped, e:
 
1345
                        if not e.args:
 
1346
                            reason = "No reason given."
 
1347
                        else:
 
1348
                            reason = e.args[0]
 
1349
                        self._do_skip(result, reason)
 
1350
                    except KeyboardInterrupt:
 
1351
                        raise
 
1352
                    except:
 
1353
                        result.addError(self, sys.exc_info())
 
1354
 
 
1355
                    try:
 
1356
                        self.tearDown()
 
1357
                        if not self._bzr_test_tearDown_run:
 
1358
                            self.fail(
 
1359
                                "test tearDown did not invoke "
 
1360
                                "bzrlib.tests.TestCase's tearDown")
 
1361
                    except KeyboardInterrupt:
 
1362
                        raise
 
1363
                    except:
 
1364
                        result.addError(self, sys.exc_info())
 
1365
                        ok = False
 
1366
                    if ok: result.addSuccess(self)
 
1367
                finally:
 
1368
                    result.stopTest(self)
 
1369
                return
 
1370
            except TestNotApplicable:
 
1371
                # Not moved from the result [yet].
 
1372
                raise
 
1373
            except KeyboardInterrupt:
 
1374
                raise
1298
1375
        finally:
1299
1376
            saved_attrs = {}
1300
1377
            absent_attr = object()
1305
1382
            self.__dict__ = saved_attrs
1306
1383
 
1307
1384
    def tearDown(self):
 
1385
        self._bzr_test_tearDown_run = True
1308
1386
        self._runCleanups()
 
1387
        self._log_contents = ''
1309
1388
        unittest.TestCase.tearDown(self)
1310
1389
 
1311
1390
    def time(self, callable, *args, **kwargs):
1312
1391
        """Run callable and accrue the time it takes to the benchmark time.
1313
 
        
 
1392
 
1314
1393
        If lsprofiling is enabled (i.e. by --lsprof-time to bzr selftest) then
1315
1394
        this will cause lsprofile statistics to be gathered and stored in
1316
1395
        self._benchcalls.
1331
1410
            self._benchtime += time.time() - start
1332
1411
 
1333
1412
    def _runCleanups(self):
1334
 
        """Run registered cleanup functions. 
 
1413
        """Run registered cleanup functions.
1335
1414
 
1336
1415
        This should only be called from TestCase.tearDown.
1337
1416
        """
1338
 
        # TODO: Perhaps this should keep running cleanups even if 
 
1417
        # TODO: Perhaps this should keep running cleanups even if
1339
1418
        # one of them fails?
1340
1419
 
1341
1420
        # Actually pop the cleanups from the list so tearDown running
1457
1536
        passed in three ways:
1458
1537
 
1459
1538
        1- A list of strings, eg ["commit", "a"].  This is recommended
1460
 
        when the command contains whitespace or metacharacters, or 
 
1539
        when the command contains whitespace or metacharacters, or
1461
1540
        is built up at run time.
1462
1541
 
1463
 
        2- A single string, eg "add a".  This is the most convenient 
 
1542
        2- A single string, eg "add a".  This is the most convenient
1464
1543
        for hardcoded commands.
1465
1544
 
1466
1545
        This runs bzr through the interface that catches and reports
1525
1604
    def run_bzr_subprocess(self, *args, **kwargs):
1526
1605
        """Run bzr in a subprocess for testing.
1527
1606
 
1528
 
        This starts a new Python interpreter and runs bzr in there. 
 
1607
        This starts a new Python interpreter and runs bzr in there.
1529
1608
        This should only be used for tests that have a justifiable need for
1530
1609
        this isolation: e.g. they are testing startup time, or signal
1531
 
        handling, or early startup code, etc.  Subprocess code can't be 
 
1610
        handling, or early startup code, etc.  Subprocess code can't be
1532
1611
        profiled or debugged so easily.
1533
1612
 
1534
1613
        :keyword retcode: The status code that is expected.  Defaults to 0.  If
1750
1829
        return sio
1751
1830
 
1752
1831
 
 
1832
class CapturedCall(object):
 
1833
    """A helper for capturing smart server calls for easy debug analysis."""
 
1834
 
 
1835
    def __init__(self, params, prefix_length):
 
1836
        """Capture the call with params and skip prefix_length stack frames."""
 
1837
        self.call = params
 
1838
        import traceback
 
1839
        # The last 5 frames are the __init__, the hook frame, and 3 smart
 
1840
        # client frames. Beyond this we could get more clever, but this is good
 
1841
        # enough for now.
 
1842
        stack = traceback.extract_stack()[prefix_length:-5]
 
1843
        self.stack = ''.join(traceback.format_list(stack))
 
1844
 
 
1845
    def __str__(self):
 
1846
        return self.call.method
 
1847
 
 
1848
    def __repr__(self):
 
1849
        return self.call.method
 
1850
 
 
1851
    def stack(self):
 
1852
        return self.stack
 
1853
 
 
1854
 
1753
1855
class TestCaseWithMemoryTransport(TestCase):
1754
1856
    """Common test class for tests that do not need disk resources.
1755
1857
 
1774
1876
 
1775
1877
    def __init__(self, methodName='runTest'):
1776
1878
        # allow test parameterization after test construction and before test
1777
 
        # execution. Variables that the parameterizer sets need to be 
 
1879
        # execution. Variables that the parameterizer sets need to be
1778
1880
        # ones that are not set by setUp, or setUp will trash them.
1779
1881
        super(TestCaseWithMemoryTransport, self).__init__(methodName)
1780
1882
        self.vfs_transport_factory = default_transport
1787
1889
 
1788
1890
        This transport is for the test scratch space relative to
1789
1891
        "self._test_root"
1790
 
        
 
1892
 
1791
1893
        :param relpath: a path relative to the base url.
1792
1894
        """
1793
1895
        t = get_transport(self.get_url(relpath))
1796
1898
 
1797
1899
    def get_readonly_transport(self, relpath=None):
1798
1900
        """Return a readonly transport for the test scratch space
1799
 
        
 
1901
 
1800
1902
        This can be used to test that operations which should only need
1801
1903
        readonly access in fact do not try to write.
1802
1904
 
1833
1935
    def get_readonly_url(self, relpath=None):
1834
1936
        """Get a URL for the readonly transport.
1835
1937
 
1836
 
        This will either be backed by '.' or a decorator to the transport 
 
1938
        This will either be backed by '.' or a decorator to the transport
1837
1939
        used by self.get_url()
1838
1940
        relpath provides for clients to get a path relative to the base url.
1839
1941
        These should only be downwards relative, not upwards.
1972
2074
 
1973
2075
    def makeAndChdirToTestDir(self):
1974
2076
        """Create a temporary directories for this one test.
1975
 
        
 
2077
 
1976
2078
        This must set self.test_home_dir and self.test_dir and chdir to
1977
2079
        self.test_dir.
1978
 
        
 
2080
 
1979
2081
        For TestCaseWithMemoryTransport we chdir to the TEST_ROOT for this test.
1980
2082
        """
1981
2083
        os.chdir(TestCaseWithMemoryTransport.TEST_ROOT)
1982
2084
        self.test_dir = TestCaseWithMemoryTransport.TEST_ROOT
1983
2085
        self.test_home_dir = self.test_dir + "/MemoryTransportMissingHomeDir"
1984
 
        
 
2086
 
1985
2087
    def make_branch(self, relpath, format=None):
1986
2088
        """Create a branch on the transport at relpath."""
1987
2089
        repo = self.make_repository(relpath, format=format)
2005
2107
 
2006
2108
    def make_repository(self, relpath, shared=False, format=None):
2007
2109
        """Create a repository on our default transport at relpath.
2008
 
        
 
2110
 
2009
2111
        Note that relpath must be a relative path, not a full url.
2010
2112
        """
2011
2113
        # FIXME: If you create a remoterepository this returns the underlying
2012
 
        # real format, which is incorrect.  Actually we should make sure that 
 
2114
        # real format, which is incorrect.  Actually we should make sure that
2013
2115
        # RemoteBzrDir returns a RemoteRepository.
2014
2116
        # maybe  mbp 20070410
2015
2117
        made_control = self.make_bzrdir(relpath, format=format)
2016
2118
        return made_control.create_repository(shared=shared)
2017
2119
 
 
2120
    def make_smart_server(self, path):
 
2121
        smart_server = server.SmartTCPServer_for_testing()
 
2122
        smart_server.setUp(self.get_server())
 
2123
        remote_transport = get_transport(smart_server.get_url()).clone(path)
 
2124
        self.addCleanup(smart_server.tearDown)
 
2125
        return remote_transport
 
2126
 
2018
2127
    def make_branch_and_memory_tree(self, relpath, format=None):
2019
2128
        """Create a branch on the default transport and a MemoryTree for it."""
2020
2129
        b = self.make_branch(relpath, format=format)
2021
2130
        return memorytree.MemoryTree.create_on_branch(b)
2022
2131
 
2023
2132
    def make_branch_builder(self, relpath, format=None):
2024
 
        url = self.get_url(relpath)
2025
 
        tran = get_transport(url)
2026
 
        return branchbuilder.BranchBuilder(get_transport(url), format=format)
 
2133
        return branchbuilder.BranchBuilder(self.get_transport(relpath),
 
2134
            format=format)
2027
2135
 
2028
2136
    def overrideEnvironmentForTesting(self):
2029
2137
        os.environ['HOME'] = self.test_home_dir
2030
2138
        os.environ['BZR_HOME'] = self.test_home_dir
2031
 
        
 
2139
 
2032
2140
    def setUp(self):
2033
2141
        super(TestCaseWithMemoryTransport, self).setUp()
2034
2142
        self._make_test_root()
2046
2154
        """Sets up a smart server as the transport server with a call log."""
2047
2155
        self.transport_server = server.SmartTCPServer_for_testing
2048
2156
        self.hpss_calls = []
 
2157
        import traceback
 
2158
        # Skip the current stack down to the caller of
 
2159
        # setup_smart_server_with_call_log
 
2160
        prefix_length = len(traceback.extract_stack()) - 2
2049
2161
        def capture_hpss_call(params):
2050
 
            import traceback
2051
 
            self.hpss_calls.append((params, traceback.format_stack()))
 
2162
            self.hpss_calls.append(
 
2163
                CapturedCall(params, prefix_length))
2052
2164
        client._SmartClient.hooks.install_named_hook(
2053
2165
            'call', capture_hpss_call, None)
2054
2166
 
2055
2167
    def reset_smart_call_log(self):
2056
2168
        self.hpss_calls = []
2057
2169
 
2058
 
     
 
2170
 
2059
2171
class TestCaseInTempDir(TestCaseWithMemoryTransport):
2060
2172
    """Derived class that runs a test within a temporary directory.
2061
2173
 
2066
2178
    All test cases create their own directory within that.  If the
2067
2179
    tests complete successfully, the directory is removed.
2068
2180
 
2069
 
    :ivar test_base_dir: The path of the top-level directory for this 
 
2181
    :ivar test_base_dir: The path of the top-level directory for this
2070
2182
    test, which contains a home directory and a work directory.
2071
2183
 
2072
2184
    :ivar test_home_dir: An initially empty directory under test_base_dir
2098
2210
 
2099
2211
    def makeAndChdirToTestDir(self):
2100
2212
        """See TestCaseWithMemoryTransport.makeAndChdirToTestDir().
2101
 
        
 
2213
 
2102
2214
        For TestCaseInTempDir we create a temporary directory based on the test
2103
2215
        name and then create two subdirs - test and home under it.
2104
2216
        """
2105
 
        name_prefix = osutils.pathjoin(self.TEST_ROOT, self._getTestDirPrefix())
 
2217
        name_prefix = osutils.pathjoin(TestCaseWithMemoryTransport.TEST_ROOT,
 
2218
            self._getTestDirPrefix())
2106
2219
        name = name_prefix
2107
2220
        for i in range(100):
2108
2221
            if os.path.exists(name):
2126
2239
        self.addCleanup(self.deleteTestDir)
2127
2240
 
2128
2241
    def deleteTestDir(self):
2129
 
        os.chdir(self.TEST_ROOT)
 
2242
        os.chdir(TestCaseWithMemoryTransport.TEST_ROOT)
2130
2243
        _rmtree_temp_dir(self.test_base_dir)
2131
2244
 
2132
2245
    def build_tree(self, shape, line_endings='binary', transport=None):
2203
2316
    ReadonlyTransportDecorator is used instead which allows the use of non disk
2204
2317
    based read write transports.
2205
2318
 
2206
 
    If an explicit class is provided for readonly access, that server and the 
 
2319
    If an explicit class is provided for readonly access, that server and the
2207
2320
    readwrite one must both define get_url() as resolving to os.getcwd().
2208
2321
    """
2209
2322
 
2295
2408
    for readonly urls.
2296
2409
 
2297
2410
    TODO RBC 20060127: make this an option to TestCaseWithTransport so it can
2298
 
                       be used without needed to redo it when a different 
 
2411
                       be used without needed to redo it when a different
2299
2412
                       subclass is in use ?
2300
2413
    """
2301
2414
 
2307
2420
 
2308
2421
def condition_id_re(pattern):
2309
2422
    """Create a condition filter which performs a re check on a test's id.
2310
 
    
 
2423
 
2311
2424
    :param pattern: A regular expression string.
2312
2425
    :return: A callable that returns True if the re matches.
2313
2426
    """
2314
 
    filter_re = re.compile(pattern)
 
2427
    filter_re = osutils.re_compile_checked(pattern, 0,
 
2428
        'test filter')
2315
2429
    def condition(test):
2316
2430
        test_id = test.id()
2317
2431
        return filter_re.search(test_id)
2320
2434
 
2321
2435
def condition_isinstance(klass_or_klass_list):
2322
2436
    """Create a condition filter which returns isinstance(param, klass).
2323
 
    
 
2437
 
2324
2438
    :return: A callable which when called with one parameter obj return the
2325
2439
        result of isinstance(obj, klass_or_klass_list).
2326
2440
    """
2331
2445
 
2332
2446
def condition_id_in_list(id_list):
2333
2447
    """Create a condition filter which verify that test's id in a list.
2334
 
    
 
2448
 
2335
2449
    :param id_list: A TestIdList object.
2336
2450
    :return: A callable that returns True if the test's id appears in the list.
2337
2451
    """
2342
2456
 
2343
2457
def condition_id_startswith(starts):
2344
2458
    """Create a condition filter verifying that test's id starts with a string.
2345
 
    
 
2459
 
2346
2460
    :param starts: A list of string.
2347
 
    :return: A callable that returns True if the test's id starts with one of 
 
2461
    :return: A callable that returns True if the test's id starts with one of
2348
2462
        the given strings.
2349
2463
    """
2350
2464
    def condition(test):
2373
2487
 
2374
2488
def filter_suite_by_condition(suite, condition):
2375
2489
    """Create a test suite by filtering another one.
2376
 
    
 
2490
 
2377
2491
    :param suite: The source suite.
2378
2492
    :param condition: A callable whose result evaluates True when called with a
2379
2493
        test case which should be included in the result.
2389
2503
 
2390
2504
def filter_suite_by_re(suite, pattern):
2391
2505
    """Create a test suite by filtering another one.
2392
 
    
 
2506
 
2393
2507
    :param suite:           the source suite
2394
2508
    :param pattern:         pattern that names must match
2395
2509
    :returns: the newly created suite
2447
2561
 
2448
2562
def randomize_suite(suite):
2449
2563
    """Return a new TestSuite with suite's tests in random order.
2450
 
    
 
2564
 
2451
2565
    The tests in the input suite are flattened into a single suite in order to
2452
2566
    accomplish this. Any nested TestSuites are removed to provide global
2453
2567
    randomness.
2459
2573
 
2460
2574
def split_suite_by_condition(suite, condition):
2461
2575
    """Split a test suite into two by a condition.
2462
 
    
 
2576
 
2463
2577
    :param suite: The suite to split.
2464
2578
    :param condition: The condition to match on. Tests that match this
2465
2579
        condition are returned in the first test suite, ones that do not match
2481
2595
 
2482
2596
def split_suite_by_re(suite, pattern):
2483
2597
    """Split a test suite into two by a regular expression.
2484
 
    
 
2598
 
2485
2599
    :param suite: The suite to split.
2486
2600
    :param pattern: A regular expression string. Test ids that match this
2487
2601
        pattern will be in the first test suite returned, and the others in the
2502
2616
              random_seed=None,
2503
2617
              exclude_pattern=None,
2504
2618
              strict=False,
2505
 
              runner_class=None):
 
2619
              runner_class=None,
 
2620
              suite_decorators=None):
2506
2621
    """Run a test suite for bzr selftest.
2507
2622
 
2508
2623
    :param runner_class: The class of runner to use. Must support the
2524
2639
                            list_only=list_only,
2525
2640
                            )
2526
2641
    runner.stop_on_failure=stop_on_failure
2527
 
    # Initialise the random number generator and display the seed used.
2528
 
    # We convert the seed to a long to make it reuseable across invocations.
2529
 
    random_order = False
2530
 
    if random_seed is not None:
2531
 
        random_order = True
2532
 
        if random_seed == "now":
2533
 
            random_seed = long(time.time())
 
2642
    # built in decorator factories:
 
2643
    decorators = [
 
2644
        random_order(random_seed, runner),
 
2645
        exclude_tests(exclude_pattern),
 
2646
        ]
 
2647
    if matching_tests_first:
 
2648
        decorators.append(tests_first(pattern))
 
2649
    else:
 
2650
        decorators.append(filter_tests(pattern))
 
2651
    if suite_decorators:
 
2652
        decorators.extend(suite_decorators)
 
2653
    for decorator in decorators:
 
2654
        suite = decorator(suite)
 
2655
    result = runner.run(suite)
 
2656
    if strict:
 
2657
        return result.wasStrictlySuccessful()
 
2658
    else:
 
2659
        return result.wasSuccessful()
 
2660
 
 
2661
 
 
2662
# A registry where get() returns a suite decorator.
 
2663
parallel_registry = registry.Registry()
 
2664
 
 
2665
 
 
2666
def fork_decorator(suite):
 
2667
    concurrency = local_concurrency()
 
2668
    if concurrency == 1:
 
2669
        return suite
 
2670
    from testtools import ConcurrentTestSuite
 
2671
    return ConcurrentTestSuite(suite, fork_for_tests)
 
2672
parallel_registry.register('fork', fork_decorator)
 
2673
 
 
2674
 
 
2675
def subprocess_decorator(suite):
 
2676
    concurrency = local_concurrency()
 
2677
    if concurrency == 1:
 
2678
        return suite
 
2679
    from testtools import ConcurrentTestSuite
 
2680
    return ConcurrentTestSuite(suite, reinvoke_for_tests)
 
2681
parallel_registry.register('subprocess', subprocess_decorator)
 
2682
 
 
2683
 
 
2684
def exclude_tests(exclude_pattern):
 
2685
    """Return a test suite decorator that excludes tests."""
 
2686
    if exclude_pattern is None:
 
2687
        return identity_decorator
 
2688
    def decorator(suite):
 
2689
        return ExcludeDecorator(suite, exclude_pattern)
 
2690
    return decorator
 
2691
 
 
2692
 
 
2693
def filter_tests(pattern):
 
2694
    if pattern == '.*':
 
2695
        return identity_decorator
 
2696
    def decorator(suite):
 
2697
        return FilterTestsDecorator(suite, pattern)
 
2698
    return decorator
 
2699
 
 
2700
 
 
2701
def random_order(random_seed, runner):
 
2702
    """Return a test suite decorator factory for randomising tests order.
 
2703
    
 
2704
    :param random_seed: now, a string which casts to a long, or a long.
 
2705
    :param runner: A test runner with a stream attribute to report on.
 
2706
    """
 
2707
    if random_seed is None:
 
2708
        return identity_decorator
 
2709
    def decorator(suite):
 
2710
        return RandomDecorator(suite, random_seed, runner.stream)
 
2711
    return decorator
 
2712
 
 
2713
 
 
2714
def tests_first(pattern):
 
2715
    if pattern == '.*':
 
2716
        return identity_decorator
 
2717
    def decorator(suite):
 
2718
        return TestFirstDecorator(suite, pattern)
 
2719
    return decorator
 
2720
 
 
2721
 
 
2722
def identity_decorator(suite):
 
2723
    """Return suite."""
 
2724
    return suite
 
2725
 
 
2726
 
 
2727
class TestDecorator(TestSuite):
 
2728
    """A decorator for TestCase/TestSuite objects.
 
2729
    
 
2730
    Usually, subclasses should override __iter__(used when flattening test
 
2731
    suites), which we do to filter, reorder, parallelise and so on, run() and
 
2732
    debug().
 
2733
    """
 
2734
 
 
2735
    def __init__(self, suite):
 
2736
        TestSuite.__init__(self)
 
2737
        self.addTest(suite)
 
2738
 
 
2739
    def countTestCases(self):
 
2740
        cases = 0
 
2741
        for test in self:
 
2742
            cases += test.countTestCases()
 
2743
        return cases
 
2744
 
 
2745
    def debug(self):
 
2746
        for test in self:
 
2747
            test.debug()
 
2748
 
 
2749
    def run(self, result):
 
2750
        # Use iteration on self, not self._tests, to allow subclasses to hook
 
2751
        # into __iter__.
 
2752
        for test in self:
 
2753
            if result.shouldStop:
 
2754
                break
 
2755
            test.run(result)
 
2756
        return result
 
2757
 
 
2758
 
 
2759
class ExcludeDecorator(TestDecorator):
 
2760
    """A decorator which excludes test matching an exclude pattern."""
 
2761
 
 
2762
    def __init__(self, suite, exclude_pattern):
 
2763
        TestDecorator.__init__(self, suite)
 
2764
        self.exclude_pattern = exclude_pattern
 
2765
        self.excluded = False
 
2766
 
 
2767
    def __iter__(self):
 
2768
        if self.excluded:
 
2769
            return iter(self._tests)
 
2770
        self.excluded = True
 
2771
        suite = exclude_tests_by_re(self, self.exclude_pattern)
 
2772
        del self._tests[:]
 
2773
        self.addTests(suite)
 
2774
        return iter(self._tests)
 
2775
 
 
2776
 
 
2777
class FilterTestsDecorator(TestDecorator):
 
2778
    """A decorator which filters tests to those matching a pattern."""
 
2779
 
 
2780
    def __init__(self, suite, pattern):
 
2781
        TestDecorator.__init__(self, suite)
 
2782
        self.pattern = pattern
 
2783
        self.filtered = False
 
2784
 
 
2785
    def __iter__(self):
 
2786
        if self.filtered:
 
2787
            return iter(self._tests)
 
2788
        self.filtered = True
 
2789
        suite = filter_suite_by_re(self, self.pattern)
 
2790
        del self._tests[:]
 
2791
        self.addTests(suite)
 
2792
        return iter(self._tests)
 
2793
 
 
2794
 
 
2795
class RandomDecorator(TestDecorator):
 
2796
    """A decorator which randomises the order of its tests."""
 
2797
 
 
2798
    def __init__(self, suite, random_seed, stream):
 
2799
        TestDecorator.__init__(self, suite)
 
2800
        self.random_seed = random_seed
 
2801
        self.randomised = False
 
2802
        self.stream = stream
 
2803
 
 
2804
    def __iter__(self):
 
2805
        if self.randomised:
 
2806
            return iter(self._tests)
 
2807
        self.randomised = True
 
2808
        self.stream.writeln("Randomizing test order using seed %s\n" %
 
2809
            (self.actual_seed()))
 
2810
        # Initialise the random number generator.
 
2811
        random.seed(self.actual_seed())
 
2812
        suite = randomize_suite(self)
 
2813
        del self._tests[:]
 
2814
        self.addTests(suite)
 
2815
        return iter(self._tests)
 
2816
 
 
2817
    def actual_seed(self):
 
2818
        if self.random_seed == "now":
 
2819
            # We convert the seed to a long to make it reuseable across
 
2820
            # invocations (because the user can reenter it).
 
2821
            self.random_seed = long(time.time())
2534
2822
        else:
2535
2823
            # Convert the seed to a long if we can
2536
2824
            try:
2537
 
                random_seed = long(random_seed)
 
2825
                self.random_seed = long(self.random_seed)
2538
2826
            except:
2539
2827
                pass
2540
 
        runner.stream.writeln("Randomizing test order using seed %s\n" %
2541
 
            (random_seed))
2542
 
        random.seed(random_seed)
2543
 
    # Customise the list of tests if requested
2544
 
    if exclude_pattern is not None:
2545
 
        suite = exclude_tests_by_re(suite, exclude_pattern)
2546
 
    if random_order:
2547
 
        order_changer = randomize_suite
2548
 
    else:
2549
 
        order_changer = preserve_input
2550
 
    if pattern != '.*' or random_order:
2551
 
        if matching_tests_first:
2552
 
            suites = map(order_changer, split_suite_by_re(suite, pattern))
2553
 
            suite = TestUtil.TestSuite(suites)
2554
 
        else:
2555
 
            suite = order_changer(filter_suite_by_re(suite, pattern))
2556
 
 
2557
 
    result = runner.run(suite)
2558
 
 
2559
 
    if strict:
2560
 
        return result.wasStrictlySuccessful()
2561
 
 
2562
 
    return result.wasSuccessful()
 
2828
        return self.random_seed
 
2829
 
 
2830
 
 
2831
class TestFirstDecorator(TestDecorator):
 
2832
    """A decorator which moves named tests to the front."""
 
2833
 
 
2834
    def __init__(self, suite, pattern):
 
2835
        TestDecorator.__init__(self, suite)
 
2836
        self.pattern = pattern
 
2837
        self.filtered = False
 
2838
 
 
2839
    def __iter__(self):
 
2840
        if self.filtered:
 
2841
            return iter(self._tests)
 
2842
        self.filtered = True
 
2843
        suites = split_suite_by_re(self, self.pattern)
 
2844
        del self._tests[:]
 
2845
        self.addTests(suites)
 
2846
        return iter(self._tests)
 
2847
 
 
2848
 
 
2849
def partition_tests(suite, count):
 
2850
    """Partition suite into count lists of tests."""
 
2851
    result = []
 
2852
    tests = list(iter_suite_tests(suite))
 
2853
    tests_per_process = int(math.ceil(float(len(tests)) / count))
 
2854
    for block in range(count):
 
2855
        low_test = block * tests_per_process
 
2856
        high_test = low_test + tests_per_process
 
2857
        process_tests = tests[low_test:high_test]
 
2858
        result.append(process_tests)
 
2859
    return result
 
2860
 
 
2861
 
 
2862
def fork_for_tests(suite):
 
2863
    """Take suite and start up one runner per CPU by forking()
 
2864
 
 
2865
    :return: An iterable of TestCase-like objects which can each have
 
2866
        run(result) called on them to feed tests to result.
 
2867
    """
 
2868
    concurrency = local_concurrency()
 
2869
    result = []
 
2870
    from subunit import TestProtocolClient, ProtocolTestCase
 
2871
    class TestInOtherProcess(ProtocolTestCase):
 
2872
        # Should be in subunit, I think. RBC.
 
2873
        def __init__(self, stream, pid):
 
2874
            ProtocolTestCase.__init__(self, stream)
 
2875
            self.pid = pid
 
2876
 
 
2877
        def run(self, result):
 
2878
            try:
 
2879
                ProtocolTestCase.run(self, result)
 
2880
            finally:
 
2881
                os.waitpid(self.pid, os.WNOHANG)
 
2882
 
 
2883
    test_blocks = partition_tests(suite, concurrency)
 
2884
    for process_tests in test_blocks:
 
2885
        process_suite = TestSuite()
 
2886
        process_suite.addTests(process_tests)
 
2887
        c2pread, c2pwrite = os.pipe()
 
2888
        pid = os.fork()
 
2889
        if pid == 0:
 
2890
            try:
 
2891
                os.close(c2pread)
 
2892
                # Leave stderr and stdout open so we can see test noise
 
2893
                # Close stdin so that the child goes away if it decides to
 
2894
                # read from stdin (otherwise its a roulette to see what
 
2895
                # child actually gets keystrokes for pdb etc).
 
2896
                sys.stdin.close()
 
2897
                sys.stdin = None
 
2898
                stream = os.fdopen(c2pwrite, 'wb', 1)
 
2899
                subunit_result = TestProtocolClient(stream)
 
2900
                process_suite.run(subunit_result)
 
2901
            finally:
 
2902
                os._exit(0)
 
2903
        else:
 
2904
            os.close(c2pwrite)
 
2905
            stream = os.fdopen(c2pread, 'rb', 1)
 
2906
            test = TestInOtherProcess(stream, pid)
 
2907
            result.append(test)
 
2908
    return result
 
2909
 
 
2910
 
 
2911
def reinvoke_for_tests(suite):
 
2912
    """Take suite and start up one runner per CPU using subprocess().
 
2913
 
 
2914
    :return: An iterable of TestCase-like objects which can each have
 
2915
        run(result) called on them to feed tests to result.
 
2916
    """
 
2917
    concurrency = local_concurrency()
 
2918
    result = []
 
2919
    from subunit import TestProtocolClient, ProtocolTestCase
 
2920
    class TestInSubprocess(ProtocolTestCase):
 
2921
        def __init__(self, process, name):
 
2922
            ProtocolTestCase.__init__(self, process.stdout)
 
2923
            self.process = process
 
2924
            self.process.stdin.close()
 
2925
            self.name = name
 
2926
 
 
2927
        def run(self, result):
 
2928
            try:
 
2929
                ProtocolTestCase.run(self, result)
 
2930
            finally:
 
2931
                self.process.wait()
 
2932
                os.unlink(self.name)
 
2933
            # print "pid %d finished" % finished_process
 
2934
    test_blocks = partition_tests(suite, concurrency)
 
2935
    for process_tests in test_blocks:
 
2936
        # ugly; currently reimplement rather than reuses TestCase methods.
 
2937
        bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
 
2938
        if not os.path.isfile(bzr_path):
 
2939
            # We are probably installed. Assume sys.argv is the right file
 
2940
            bzr_path = sys.argv[0]
 
2941
        fd, test_list_file_name = tempfile.mkstemp()
 
2942
        test_list_file = os.fdopen(fd, 'wb', 1)
 
2943
        for test in process_tests:
 
2944
            test_list_file.write(test.id() + '\n')
 
2945
        test_list_file.close()
 
2946
        try:
 
2947
            argv = [bzr_path, 'selftest', '--load-list', test_list_file_name,
 
2948
                '--subunit']
 
2949
            if '--no-plugins' in sys.argv:
 
2950
                argv.append('--no-plugins')
 
2951
            # stderr=STDOUT would be ideal, but until we prevent noise on
 
2952
            # stderr it can interrupt the subunit protocol.
 
2953
            process = Popen(argv, stdin=PIPE, stdout=PIPE, stderr=PIPE,
 
2954
                bufsize=1)
 
2955
            test = TestInSubprocess(process, test_list_file_name)
 
2956
            result.append(test)
 
2957
        except:
 
2958
            os.unlink(test_list_file_name)
 
2959
            raise
 
2960
    return result
 
2961
 
 
2962
 
 
2963
def cpucount(content):
 
2964
    lines = content.splitlines()
 
2965
    prefix = 'processor'
 
2966
    for line in lines:
 
2967
        if line.startswith(prefix):
 
2968
            concurrency = int(line[line.find(':')+1:]) + 1
 
2969
    return concurrency
 
2970
 
 
2971
 
 
2972
def local_concurrency():
 
2973
    try:
 
2974
        content = file('/proc/cpuinfo', 'rb').read()
 
2975
        concurrency = cpucount(content)
 
2976
    except Exception, e:
 
2977
        concurrency = 1
 
2978
    return concurrency
 
2979
 
 
2980
 
 
2981
class BZRTransformingResult(unittest.TestResult):
 
2982
 
 
2983
    def __init__(self, target):
 
2984
        unittest.TestResult.__init__(self)
 
2985
        self.result = target
 
2986
 
 
2987
    def startTest(self, test):
 
2988
        self.result.startTest(test)
 
2989
 
 
2990
    def stopTest(self, test):
 
2991
        self.result.stopTest(test)
 
2992
 
 
2993
    def addError(self, test, err):
 
2994
        feature = self._error_looks_like('UnavailableFeature: ', err)
 
2995
        if feature is not None:
 
2996
            self.result.addNotSupported(test, feature)
 
2997
        else:
 
2998
            self.result.addError(test, err)
 
2999
 
 
3000
    def addFailure(self, test, err):
 
3001
        known = self._error_looks_like('KnownFailure: ', err)
 
3002
        if known is not None:
 
3003
            self.result._addKnownFailure(test, [KnownFailure,
 
3004
                                                KnownFailure(known), None])
 
3005
        else:
 
3006
            self.result.addFailure(test, err)
 
3007
 
 
3008
    def addSkip(self, test, reason):
 
3009
        self.result.addSkip(test, reason)
 
3010
 
 
3011
    def addSuccess(self, test):
 
3012
        self.result.addSuccess(test)
 
3013
 
 
3014
    def _error_looks_like(self, prefix, err):
 
3015
        """Deserialize exception and returns the stringify value."""
 
3016
        import subunit
 
3017
        value = None
 
3018
        typ, exc, _ = err
 
3019
        if isinstance(exc, subunit.RemoteException):
 
3020
            # stringify the exception gives access to the remote traceback
 
3021
            # We search the last line for 'prefix'
 
3022
            lines = str(exc).split('\n')
 
3023
            if len(lines) > 1:
 
3024
                last = lines[-2] # -1 is empty, final \n
 
3025
            else:
 
3026
                last = lines[-1]
 
3027
            if last.startswith(prefix):
 
3028
                value = last[len(prefix):]
 
3029
        return value
2563
3030
 
2564
3031
 
2565
3032
# Controlled by "bzr selftest -E=..." option
2580
3047
             debug_flags=None,
2581
3048
             starting_with=None,
2582
3049
             runner_class=None,
 
3050
             suite_decorators=None,
2583
3051
             ):
2584
3052
    """Run the whole test suite under the enhanced runner"""
2585
3053
    # XXX: Very ugly way to do this...
2617
3085
                     exclude_pattern=exclude_pattern,
2618
3086
                     strict=strict,
2619
3087
                     runner_class=runner_class,
 
3088
                     suite_decorators=suite_decorators,
2620
3089
                     )
2621
3090
    finally:
2622
3091
        default_transport = old_transport
2650
3119
    """Warns about tests not appearing or appearing more than once.
2651
3120
 
2652
3121
    :param test_suite: A TestSuite object.
2653
 
    :param test_id_list: The list of test ids that should be found in 
 
3122
    :param test_id_list: The list of test ids that should be found in
2654
3123
         test_suite.
2655
3124
 
2656
3125
    :return: (absents, duplicates) absents is a list containing the test found
2798
3267
                   'bzrlib.tests.interrepository_implementations',
2799
3268
                   'bzrlib.tests.intertree_implementations',
2800
3269
                   'bzrlib.tests.inventory_implementations',
 
3270
                   'bzrlib.tests.per_interbranch',
2801
3271
                   'bzrlib.tests.per_lock',
2802
3272
                   'bzrlib.tests.per_repository',
2803
3273
                   'bzrlib.tests.per_repository_reference',
2816
3286
                   'bzrlib.tests.test_bundle',
2817
3287
                   'bzrlib.tests.test_bzrdir',
2818
3288
                   'bzrlib.tests.test_cache_utf8',
 
3289
                   'bzrlib.tests.test_clean_tree',
2819
3290
                   'bzrlib.tests.test_chunk_writer',
2820
3291
                   'bzrlib.tests.test__chunks_to_lines',
2821
3292
                   'bzrlib.tests.test_commands',
2826
3297
                   'bzrlib.tests.test_counted_lock',
2827
3298
                   'bzrlib.tests.test_decorators',
2828
3299
                   'bzrlib.tests.test_delta',
 
3300
                   'bzrlib.tests.test_debug',
2829
3301
                   'bzrlib.tests.test_deprecated_graph',
2830
3302
                   'bzrlib.tests.test_diff',
2831
3303
                   'bzrlib.tests.test_directory_service',
2832
3304
                   'bzrlib.tests.test_dirstate',
2833
3305
                   'bzrlib.tests.test_email_message',
 
3306
                   'bzrlib.tests.test_eol_filters',
2834
3307
                   'bzrlib.tests.test_errors',
 
3308
                   'bzrlib.tests.test_export',
2835
3309
                   'bzrlib.tests.test_extract',
2836
3310
                   'bzrlib.tests.test_fetch',
2837
3311
                   'bzrlib.tests.test_fifo_cache',
 
3312
                   'bzrlib.tests.test_filters',
2838
3313
                   'bzrlib.tests.test_ftp_transport',
2839
3314
                   'bzrlib.tests.test_foreign',
2840
3315
                   'bzrlib.tests.test_generate_docs',
2854
3329
                   'bzrlib.tests.test_index',
2855
3330
                   'bzrlib.tests.test_info',
2856
3331
                   'bzrlib.tests.test_inv',
 
3332
                   'bzrlib.tests.test_inventory_delta',
2857
3333
                   'bzrlib.tests.test_knit',
2858
3334
                   'bzrlib.tests.test_lazy_import',
2859
3335
                   'bzrlib.tests.test_lazy_regex',
2888
3364
                   'bzrlib.tests.test_reconfigure',
2889
3365
                   'bzrlib.tests.test_registry',
2890
3366
                   'bzrlib.tests.test_remote',
 
3367
                   'bzrlib.tests.test_rename_map',
2891
3368
                   'bzrlib.tests.test_repository',
2892
3369
                   'bzrlib.tests.test_revert',
2893
3370
                   'bzrlib.tests.test_revision',
2897
3374
                   'bzrlib.tests.test_rules',
2898
3375
                   'bzrlib.tests.test_sampler',
2899
3376
                   'bzrlib.tests.test_selftest',
 
3377
                   'bzrlib.tests.test_serializer',
2900
3378
                   'bzrlib.tests.test_setup',
2901
3379
                   'bzrlib.tests.test_sftp_transport',
2902
3380
                   'bzrlib.tests.test_shelf',
3005
3483
            # No tests to keep here, move along
3006
3484
            continue
3007
3485
        try:
3008
 
            # note that this really does mean "report only" -- doctest 
 
3486
            # note that this really does mean "report only" -- doctest
3009
3487
            # still runs the rest of the examples
3010
3488
            doc_suite = doctest.DocTestSuite(mod,
3011
3489
                optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
3060
3538
    return suite
3061
3539
 
3062
3540
 
3063
 
def multiply_tests_from_modules(module_name_list, scenario_iter, loader=None):
3064
 
    """Adapt all tests in some given modules to given scenarios.
3065
 
 
3066
 
    This is the recommended public interface for test parameterization.
3067
 
    Typically the test_suite() method for a per-implementation test
3068
 
    suite will call multiply_tests_from_modules and return the 
3069
 
    result.
3070
 
 
3071
 
    :param module_name_list: List of fully-qualified names of test
3072
 
        modules.
3073
 
    :param scenario_iter: Iterable of pairs of (scenario_name, 
3074
 
        scenario_param_dict).
3075
 
    :param loader: If provided, will be used instead of a new 
3076
 
        bzrlib.tests.TestLoader() instance.
3077
 
 
3078
 
    This returns a new TestSuite containing the cross product of
3079
 
    all the tests in all the modules, each repeated for each scenario.
3080
 
    Each test is adapted by adding the scenario name at the end 
3081
 
    of its name, and updating the test object's __dict__ with the
3082
 
    scenario_param_dict.
3083
 
 
3084
 
    >>> r = multiply_tests_from_modules(
3085
 
    ...     ['bzrlib.tests.test_sampler'],
3086
 
    ...     [('one', dict(param=1)), 
3087
 
    ...      ('two', dict(param=2))])
3088
 
    >>> tests = list(iter_suite_tests(r))
3089
 
    >>> len(tests)
3090
 
    2
3091
 
    >>> tests[0].id()
3092
 
    'bzrlib.tests.test_sampler.DemoTest.test_nothing(one)'
3093
 
    >>> tests[0].param
3094
 
    1
3095
 
    >>> tests[1].param
3096
 
    2
3097
 
    """
3098
 
    # XXX: Isn't load_tests() a better way to provide the same functionality
3099
 
    # without forcing a predefined TestScenarioApplier ? --vila 080215
3100
 
    if loader is None:
3101
 
        loader = TestUtil.TestLoader()
3102
 
 
3103
 
    suite = loader.suiteClass()
3104
 
 
3105
 
    adapter = TestScenarioApplier()
3106
 
    adapter.scenarios = list(scenario_iter)
3107
 
    adapt_modules(module_name_list, adapter, loader, suite)
3108
 
    return suite
3109
 
 
3110
 
 
3111
3541
def multiply_scenarios(scenarios_left, scenarios_right):
3112
3542
    """Multiply two sets of scenarios.
3113
3543
 
3122
3552
        for right_name, right_dict in scenarios_right]
3123
3553
 
3124
3554
 
3125
 
 
3126
 
def adapt_modules(mods_list, adapter, loader, suite):
3127
 
    """Adapt the modules in mods_list using adapter and add to suite."""
3128
 
    tests = loader.loadTestsFromModuleNames(mods_list)
3129
 
    adapt_tests(tests, adapter, suite)
3130
 
 
3131
 
 
3132
 
def adapt_tests(tests_list, adapter, suite):
3133
 
    """Adapt the tests in tests_list using adapter and add to suite."""
3134
 
    for test in iter_suite_tests(tests_list):
3135
 
        suite.addTests(adapter.adapt(test))
 
3555
def multiply_tests(tests, scenarios, result):
 
3556
    """Multiply tests_list by scenarios into result.
 
3557
 
 
3558
    This is the core workhorse for test parameterisation.
 
3559
 
 
3560
    Typically the load_tests() method for a per-implementation test suite will
 
3561
    call multiply_tests and return the result.
 
3562
 
 
3563
    :param tests: The tests to parameterise.
 
3564
    :param scenarios: The scenarios to apply: pairs of (scenario_name,
 
3565
        scenario_param_dict).
 
3566
    :param result: A TestSuite to add created tests to.
 
3567
 
 
3568
    This returns the passed in result TestSuite with the cross product of all
 
3569
    the tests repeated once for each scenario.  Each test is adapted by adding
 
3570
    the scenario name at the end of its id(), and updating the test object's
 
3571
    __dict__ with the scenario_param_dict.
 
3572
 
 
3573
    >>> import bzrlib.tests.test_sampler
 
3574
    >>> r = multiply_tests(
 
3575
    ...     bzrlib.tests.test_sampler.DemoTest('test_nothing'),
 
3576
    ...     [('one', dict(param=1)),
 
3577
    ...      ('two', dict(param=2))],
 
3578
    ...     TestSuite())
 
3579
    >>> tests = list(iter_suite_tests(r))
 
3580
    >>> len(tests)
 
3581
    2
 
3582
    >>> tests[0].id()
 
3583
    'bzrlib.tests.test_sampler.DemoTest.test_nothing(one)'
 
3584
    >>> tests[0].param
 
3585
    1
 
3586
    >>> tests[1].param
 
3587
    2
 
3588
    """
 
3589
    for test in iter_suite_tests(tests):
 
3590
        apply_scenarios(test, scenarios, result)
 
3591
    return result
 
3592
 
 
3593
 
 
3594
def apply_scenarios(test, scenarios, result):
 
3595
    """Apply the scenarios in scenarios to test and add to result.
 
3596
 
 
3597
    :param test: The test to apply scenarios to.
 
3598
    :param scenarios: An iterable of scenarios to apply to test.
 
3599
    :return: result
 
3600
    :seealso: apply_scenario
 
3601
    """
 
3602
    for scenario in scenarios:
 
3603
        result.addTest(apply_scenario(test, scenario))
 
3604
    return result
 
3605
 
 
3606
 
 
3607
def apply_scenario(test, scenario):
 
3608
    """Copy test and apply scenario to it.
 
3609
 
 
3610
    :param test: A test to adapt.
 
3611
    :param scenario: A tuple describing the scenarion.
 
3612
        The first element of the tuple is the new test id.
 
3613
        The second element is a dict containing attributes to set on the
 
3614
        test.
 
3615
    :return: The adapted test.
 
3616
    """
 
3617
    new_id = "%s(%s)" % (test.id(), scenario[0])
 
3618
    new_test = clone_test(test, new_id)
 
3619
    for name, value in scenario[1].items():
 
3620
        setattr(new_test, name, value)
 
3621
    return new_test
 
3622
 
 
3623
 
 
3624
def clone_test(test, new_id):
 
3625
    """Clone a test giving it a new id.
 
3626
 
 
3627
    :param test: The test to clone.
 
3628
    :param new_id: The id to assign to it.
 
3629
    :return: The new test.
 
3630
    """
 
3631
    from copy import deepcopy
 
3632
    new_test = deepcopy(test)
 
3633
    new_test.id = lambda: new_id
 
3634
    return new_test
3136
3635
 
3137
3636
 
3138
3637
def _rmtree_temp_dir(dirname):
3243
3742
UnicodeFilenameFeature = _UnicodeFilenameFeature()
3244
3743
 
3245
3744
 
3246
 
class TestScenarioApplier(object):
3247
 
    """A tool to apply scenarios to tests."""
3248
 
 
3249
 
    def adapt(self, test):
3250
 
        """Return a TestSuite containing a copy of test for each scenario."""
3251
 
        result = unittest.TestSuite()
3252
 
        for scenario in self.scenarios:
3253
 
            result.addTest(self.adapt_test_to_scenario(test, scenario))
3254
 
        return result
3255
 
 
3256
 
    def adapt_test_to_scenario(self, test, scenario):
3257
 
        """Copy test and apply scenario to it.
3258
 
 
3259
 
        :param test: A test to adapt.
3260
 
        :param scenario: A tuple describing the scenarion.
3261
 
            The first element of the tuple is the new test id.
3262
 
            The second element is a dict containing attributes to set on the
3263
 
            test.
3264
 
        :return: The adapted test.
3265
 
        """
3266
 
        from copy import deepcopy
3267
 
        new_test = deepcopy(test)
3268
 
        for name, value in scenario[1].items():
3269
 
            setattr(new_test, name, value)
3270
 
        new_id = "%s(%s)" % (new_test.id(), scenario[0])
3271
 
        new_test.id = lambda: new_id
3272
 
        return new_test
3273
 
 
3274
 
 
3275
3745
def probe_unicode_in_user_encoding():
3276
3746
    """Try to encode several unicode strings to use in unicode-aware tests.
3277
3747
    Return first successfull match.
3305
3775
    return None
3306
3776
 
3307
3777
 
3308
 
class _FTPServerFeature(Feature):
3309
 
    """Some tests want an FTP Server, check if one is available.
3310
 
 
3311
 
    Right now, the only way this is available is if 'medusa' is installed.
3312
 
    http://www.amk.ca/python/code/medusa.html
3313
 
    """
3314
 
 
3315
 
    def _probe(self):
3316
 
        try:
3317
 
            import bzrlib.tests.ftp_server
3318
 
            return True
3319
 
        except ImportError:
3320
 
            return False
3321
 
 
3322
 
    def feature_name(self):
3323
 
        return 'FTPServer'
3324
 
 
3325
 
 
3326
 
FTPServerFeature = _FTPServerFeature()
3327
 
 
3328
 
 
3329
3778
class _HTTPSServerFeature(Feature):
3330
3779
    """Some tests want an https Server, check if one is available.
3331
3780
 
3431
3880
        return 'case-insensitive filesystem'
3432
3881
 
3433
3882
CaseInsensitiveFilesystemFeature = _CaseInsensitiveFilesystemFeature()
 
3883
 
 
3884
 
 
3885
class _SubUnitFeature(Feature):
 
3886
    """Check if subunit is available."""
 
3887
 
 
3888
    def _probe(self):
 
3889
        try:
 
3890
            import subunit
 
3891
            return True
 
3892
        except ImportError:
 
3893
            return False
 
3894
 
 
3895
    def feature_name(self):
 
3896
        return 'subunit'
 
3897
 
 
3898
SubUnitFeature = _SubUnitFeature()
 
3899
# Only define SubUnitBzrRunner if subunit is available.
 
3900
try:
 
3901
    from subunit import TestProtocolClient
 
3902
    class SubUnitBzrRunner(TextTestRunner):
 
3903
        def run(self, test):
 
3904
            # undo out claim for testing which looks like a test start to subunit
 
3905
            self.stream.write("success: %s\n" % (osutils.realpath(sys.argv[0]),))
 
3906
            result = TestProtocolClient(self.stream)
 
3907
            test.run(result)
 
3908
            return result
 
3909
except ImportError:
 
3910
    pass