/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: John Arbash Meinel
  • Date: 2007-07-11 23:45:20 UTC
  • mfrom: (2601 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2643.
  • Revision ID: john@arbash-meinel.com-20070711234520-do3h7zw8skbathpz
[merge] bzr.dev 2601

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
# general style of bzrlib.  Please continue that consistency when adding e.g.
27
27
# new assertFoo() methods.
28
28
 
 
29
import atexit
29
30
import codecs
30
31
from cStringIO import StringIO
31
32
import difflib
36
37
from pprint import pformat
37
38
import random
38
39
import re
 
40
import shlex
39
41
import stat
40
42
from subprocess import Popen, PIPE
41
43
import sys
42
44
import tempfile
43
45
import unittest
44
46
import time
 
47
import warnings
45
48
 
46
49
 
47
50
from bzrlib import (
74
77
from bzrlib.revision import common_ancestor
75
78
import bzrlib.store
76
79
from bzrlib import symbol_versioning
 
80
from bzrlib.symbol_versioning import (
 
81
    deprecated_method,
 
82
    zero_eighteen,
 
83
    )
77
84
import bzrlib.trace
78
85
from bzrlib.transport import get_transport
79
86
import bzrlib.transport
499
506
                 stream=sys.stderr,
500
507
                 descriptions=0,
501
508
                 verbosity=1,
502
 
                 keep_output=False,
503
509
                 bench_history=None,
504
510
                 use_numbered_dirs=False,
505
511
                 list_only=False
507
513
        self.stream = unittest._WritelnDecorator(stream)
508
514
        self.descriptions = descriptions
509
515
        self.verbosity = verbosity
510
 
        self.keep_output = keep_output
511
516
        self._bench_history = bench_history
512
517
        self.use_numbered_dirs = use_numbered_dirs
513
518
        self.list_only = list_only
574
579
            for feature, count in sorted(result.unsupported.items()):
575
580
                self.stream.writeln("Missing feature '%s' skipped %d tests." %
576
581
                    (feature, count))
577
 
        result.report_cleaning_up()
578
 
        # This is still a little bogus, 
579
 
        # but only a little. Folk not using our testrunner will
580
 
        # have to delete their temp directories themselves.
581
 
        test_root = TestCaseWithMemoryTransport.TEST_ROOT
582
 
        if result.wasSuccessful() or not self.keep_output:
583
 
            if test_root is not None:
584
 
                # If LANG=C we probably have created some bogus paths
585
 
                # which rmtree(unicode) will fail to delete
586
 
                # so make sure we are using rmtree(str) to delete everything
587
 
                # except on win32, where rmtree(str) will fail
588
 
                # since it doesn't have the property of byte-stream paths
589
 
                # (they are either ascii or mbcs)
590
 
                if sys.platform == 'win32':
591
 
                    # make sure we are using the unicode win32 api
592
 
                    test_root = unicode(test_root)
593
 
                else:
594
 
                    test_root = test_root.encode(
595
 
                        sys.getfilesystemencoding())
596
 
                _rmtree_temp_dir(test_root)
597
 
        else:
598
 
            note("Failed tests working directories are in '%s'\n", test_root)
599
 
        TestCaseWithMemoryTransport.TEST_ROOT = None
600
582
        result.finished()
601
583
        return result
602
584
 
721
703
    def get_non_echoed_password(self, prompt):
722
704
        """Get password from stdin without trying to handle the echo mode"""
723
705
        if prompt:
724
 
            self.stdout.write(prompt)
 
706
            self.stdout.write(prompt.encode(self.stdout.encoding, 'replace'))
725
707
        password = self.stdin.readline()
726
708
        if not password:
727
709
            raise EOFError
770
752
        self._benchcalls = []
771
753
        self._benchtime = None
772
754
        self._clear_hooks()
 
755
        self._clear_debug_flags()
 
756
 
 
757
    def _clear_debug_flags(self):
 
758
        """Prevent externally set debug flags affecting tests.
 
759
        
 
760
        Tests that want to use debug flags can just set them in the
 
761
        debug_flags set during setup/teardown.
 
762
        """
 
763
        self._preserved_debug_flags = set(debug.debug_flags)
 
764
        debug.debug_flags.clear()
 
765
        self.addCleanup(self._restore_debug_flags)
773
766
 
774
767
    def _clear_hooks(self):
775
768
        # prevent hooks affecting tests
783
776
        # reset all hooks to an empty instance of the appropriate type
784
777
        bzrlib.branch.Branch.hooks = bzrlib.branch.BranchHooks()
785
778
        bzrlib.smart.server.SmartTCPServer.hooks = bzrlib.smart.server.SmartServerHooks()
786
 
        # FIXME: Rather than constructing new objects like this, how about
787
 
        # having save() and clear() methods on the base Hook class? mbp
788
 
        # 20070416
789
779
 
790
780
    def _silenceUI(self):
791
781
        """Turn off UI for duration of test"""
823
813
            message += '\n'
824
814
        raise AssertionError("%snot equal:\na = %s\nb = %s\n"
825
815
            % (message,
826
 
               pformat(a, indent=4), pformat(b, indent=4)))
 
816
               pformat(a), pformat(b)))
827
817
 
828
818
    assertEquals = assertEqual
829
819
 
838
828
            return
839
829
        if message is None:
840
830
            message = "texts not equal:\n"
841
 
        raise AssertionError(message + 
842
 
                             self._ndiff_strings(a, b))      
 
831
        raise AssertionError(message +
 
832
                             self._ndiff_strings(a, b))
843
833
        
844
834
    def assertEqualMode(self, mode, mode_test):
845
835
        self.assertEqual(mode, mode_test,
857
847
    def assertContainsRe(self, haystack, needle_re):
858
848
        """Assert that a contains something matching a regular expression."""
859
849
        if not re.search(needle_re, haystack):
860
 
            raise AssertionError('pattern "%r" not found in "%r"'
861
 
                    % (needle_re, haystack))
 
850
            if '\n' in haystack or len(haystack) > 60:
 
851
                # a long string, format it in a more readable way
 
852
                raise AssertionError(
 
853
                        'pattern "%s" not found in\n"""\\\n%s"""\n'
 
854
                        % (needle_re, haystack))
 
855
            else:
 
856
                raise AssertionError('pattern "%s" not found in "%s"'
 
857
                        % (needle_re, haystack))
862
858
 
863
859
    def assertNotContainsRe(self, haystack, needle_re):
864
860
        """Assert that a does not match a regular expression"""
894
890
                excName = str(excClass)
895
891
            raise self.failureException, "%s not raised" % excName
896
892
 
897
 
    def assertRaises(self, excClass, func, *args, **kwargs):
 
893
    def assertRaises(self, excClass, callableObj, *args, **kwargs):
898
894
        """Assert that a callable raises a particular exception.
899
895
 
900
896
        :param excClass: As for the except statement, this may be either an
901
 
        exception class, or a tuple of classes.
 
897
            exception class, or a tuple of classes.
 
898
        :param callableObj: A callable, will be passed ``*args`` and
 
899
            ``**kwargs``.
902
900
 
903
901
        Returns the exception so that you can examine it.
904
902
        """
905
903
        try:
906
 
            func(*args, **kwargs)
 
904
            callableObj(*args, **kwargs)
907
905
        except excClass, e:
908
906
            return e
909
907
        else:
988
986
        :param args: The positional arguments for the callable
989
987
        :param kwargs: The keyword arguments for the callable
990
988
        :return: A tuple (warnings, result). result is the result of calling
991
 
            a_callable(*args, **kwargs).
 
989
            a_callable(``*args``, ``**kwargs``).
992
990
        """
993
991
        local_warnings = []
994
992
        def capture_warnings(msg, cls=None, stacklevel=None):
1007
1005
    def applyDeprecated(self, deprecation_format, a_callable, *args, **kwargs):
1008
1006
        """Call a deprecated callable without warning the user.
1009
1007
 
 
1008
        Note that this only captures warnings raised by symbol_versioning.warn,
 
1009
        not other callers that go direct to the warning module.
 
1010
 
1010
1011
        :param deprecation_format: The deprecation format that the callable
1011
 
            should have been deprecated with. This is the same type as the 
1012
 
            parameter to deprecated_method/deprecated_function. If the 
 
1012
            should have been deprecated with. This is the same type as the
 
1013
            parameter to deprecated_method/deprecated_function. If the
1013
1014
            callable is not deprecated with this format, an assertion error
1014
1015
            will be raised.
1015
1016
        :param a_callable: A callable to call. This may be a bound method or
1016
 
            a regular function. It will be called with *args and **kwargs.
 
1017
            a regular function. It will be called with ``*args`` and
 
1018
            ``**kwargs``.
1017
1019
        :param args: The positional arguments for the callable
1018
1020
        :param kwargs: The keyword arguments for the callable
1019
 
        :return: The result of a_callable(*args, **kwargs)
 
1021
        :return: The result of a_callable(``*args``, ``**kwargs``)
1020
1022
        """
1021
1023
        call_warnings, result = self._capture_warnings(a_callable,
1022
1024
            *args, **kwargs)
1036
1038
        as it allows you to simply specify the deprecation format being used
1037
1039
        and will ensure that that is issued for the function being called.
1038
1040
 
 
1041
        Note that this only captures warnings raised by symbol_versioning.warn,
 
1042
        not other callers that go direct to the warning module.
 
1043
 
1039
1044
        :param expected: a list of the deprecation warnings expected, in order
1040
1045
        :param callable: The callable to call
1041
1046
        :param args: The positional arguments for the callable
1109
1114
            # -- vila 20061212
1110
1115
            'ftp_proxy': None,
1111
1116
            'FTP_PROXY': None,
 
1117
            'BZR_REMOTE_PATH': None,
1112
1118
        }
1113
1119
        self.__old_env = {}
1114
1120
        self.addCleanup(self._restoreEnvironment)
1119
1125
        """Set an environment variable, and reset it when finished."""
1120
1126
        self.__old_env[name] = osutils.set_or_unset_env(name, newvalue)
1121
1127
 
 
1128
    def _restore_debug_flags(self):
 
1129
        debug.debug_flags.clear()
 
1130
        debug.debug_flags.update(self._preserved_debug_flags)
 
1131
 
1122
1132
    def _restoreEnvironment(self):
1123
1133
        for name, value in self.__old_env.iteritems():
1124
1134
            osutils.set_or_unset_env(name, value)
1215
1225
        else:
1216
1226
            return "DELETED log file to reduce memory footprint"
1217
1227
 
 
1228
    @deprecated_method(zero_eighteen)
1218
1229
    def capture(self, cmd, retcode=0):
1219
1230
        """Shortcut that splits cmd into words, runs, and returns stdout"""
1220
1231
        return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
1227
1238
        if not feature.available():
1228
1239
            raise UnavailableFeature(feature)
1229
1240
 
 
1241
    @deprecated_method(zero_eighteen)
1230
1242
    def run_bzr_captured(self, argv, retcode=0, encoding=None, stdin=None,
1231
1243
                         working_dir=None):
1232
1244
        """Invoke bzr and return (stdout, stderr).
1233
1245
 
1234
 
        Useful for code that wants to check the contents of the
1235
 
        output, the way error messages are presented, etc.
1236
 
 
1237
 
        This should be the main method for tests that want to exercise the
1238
 
        overall behavior of the bzr application (rather than a unit test
1239
 
        or a functional test of the library.)
1240
 
 
1241
 
        Much of the old code runs bzr by forking a new copy of Python, but
1242
 
        that is slower, harder to debug, and generally not necessary.
1243
 
 
1244
 
        This runs bzr through the interface that catches and reports
1245
 
        errors, and with logging set to something approximating the
1246
 
        default, so that error reporting can be checked.
1247
 
 
1248
 
        :param argv: arguments to invoke bzr
1249
 
        :param retcode: expected return code, or None for don't-care.
1250
 
        :param encoding: encoding for sys.stdout and sys.stderr
 
1246
        Don't call this method, just use run_bzr() which is equivalent.
 
1247
 
 
1248
        :param argv: Arguments to invoke bzr.  This may be either a 
 
1249
            single string, in which case it is split by shlex into words, 
 
1250
            or a list of arguments.
 
1251
        :param retcode: Expected return code, or None for don't-care.
 
1252
        :param encoding: Encoding for sys.stdout and sys.stderr
1251
1253
        :param stdin: A string to be used as stdin for the command.
1252
1254
        :param working_dir: Change to this directory before running
1253
1255
        """
 
1256
        return self._run_bzr_autosplit(argv, retcode=retcode,
 
1257
                encoding=encoding, stdin=stdin, working_dir=working_dir,
 
1258
                )
 
1259
 
 
1260
    def _run_bzr_autosplit(self, args, retcode, encoding, stdin,
 
1261
            working_dir):
 
1262
        """Run bazaar command line, splitting up a string command line."""
 
1263
        if isinstance(args, basestring):
 
1264
            args = list(shlex.split(args))
 
1265
        return self._run_bzr_core(args, retcode=retcode,
 
1266
                encoding=encoding, stdin=stdin, working_dir=working_dir,
 
1267
                )
 
1268
 
 
1269
    def _run_bzr_core(self, args, retcode, encoding, stdin,
 
1270
            working_dir):
1254
1271
        if encoding is None:
1255
1272
            encoding = bzrlib.user_encoding
1256
1273
        stdout = StringIOWrapper()
1258
1275
        stdout.encoding = encoding
1259
1276
        stderr.encoding = encoding
1260
1277
 
1261
 
        self.log('run bzr: %r', argv)
 
1278
        self.log('run bzr: %r', args)
1262
1279
        # FIXME: don't call into logging here
1263
1280
        handler = logging.StreamHandler(stderr)
1264
1281
        handler.setLevel(logging.INFO)
1273
1290
            os.chdir(working_dir)
1274
1291
 
1275
1292
        try:
1276
 
            saved_debug_flags = frozenset(debug.debug_flags)
1277
 
            debug.debug_flags.clear()
1278
 
            try:
1279
 
                result = self.apply_redirected(ui.ui_factory.stdin,
1280
 
                                               stdout, stderr,
1281
 
                                               bzrlib.commands.run_bzr_catch_errors,
1282
 
                                               argv)
1283
 
            finally:
1284
 
                debug.debug_flags.update(saved_debug_flags)
 
1293
            result = self.apply_redirected(ui.ui_factory.stdin,
 
1294
                stdout, stderr,
 
1295
                bzrlib.commands.run_bzr_catch_errors,
 
1296
                args)
1285
1297
        finally:
1286
1298
            logger.removeHandler(handler)
1287
1299
            ui.ui_factory = old_ui_factory
1302
1314
    def run_bzr(self, *args, **kwargs):
1303
1315
        """Invoke bzr, as if it were run from the command line.
1304
1316
 
 
1317
        The argument list should not include the bzr program name - the
 
1318
        first argument is normally the bzr command.  Arguments may be
 
1319
        passed in three ways:
 
1320
 
 
1321
        1- A list of strings, eg ["commit", "a"].  This is recommended
 
1322
        when the command contains whitespace or metacharacters, or 
 
1323
        is built up at run time.
 
1324
 
 
1325
        2- A single string, eg "add a".  This is the most convenient 
 
1326
        for hardcoded commands.
 
1327
 
 
1328
        3- Several varargs parameters, eg run_bzr("add", "a").  
 
1329
        This is not recommended for new code.
 
1330
 
 
1331
        This runs bzr through the interface that catches and reports
 
1332
        errors, and with logging set to something approximating the
 
1333
        default, so that error reporting can be checked.
 
1334
 
1305
1335
        This should be the main method for tests that want to exercise the
1306
1336
        overall behavior of the bzr application (rather than a unit test
1307
1337
        or a functional test of the library.)
1309
1339
        This sends the stdout/stderr results into the test's log,
1310
1340
        where it may be useful for debugging.  See also run_captured.
1311
1341
 
1312
 
        :param stdin: A string to be used as stdin for the command.
1313
 
        :param retcode: The status code the command should return
1314
 
        :param working_dir: The directory to run the command in
 
1342
        :keyword stdin: A string to be used as stdin for the command.
 
1343
        :keyword retcode: The status code the command should return;
 
1344
            default 0.
 
1345
        :keyword working_dir: The directory to run the command in
 
1346
        :keyword error_regexes: A list of expected error messages.  If
 
1347
            specified they must be seen in the error output of the command.
1315
1348
        """
1316
1349
        retcode = kwargs.pop('retcode', 0)
1317
1350
        encoding = kwargs.pop('encoding', None)
1319
1352
        working_dir = kwargs.pop('working_dir', None)
1320
1353
        error_regexes = kwargs.pop('error_regexes', [])
1321
1354
 
1322
 
        out, err = self.run_bzr_captured(args, retcode=retcode,
1323
 
            encoding=encoding, stdin=stdin, working_dir=working_dir)
 
1355
        if len(args) == 1:
 
1356
            if isinstance(args[0], (list, basestring)):
 
1357
                args = args[0]
 
1358
        else:
 
1359
            symbol_versioning.warn(zero_eighteen % "passing varargs to run_bzr",
 
1360
                                   DeprecationWarning, stacklevel=3)
 
1361
 
 
1362
        out, err = self._run_bzr_autosplit(args=args,
 
1363
            retcode=retcode,
 
1364
            encoding=encoding, stdin=stdin, working_dir=working_dir,
 
1365
            )
1324
1366
 
1325
1367
        for regex in error_regexes:
1326
1368
            self.assertContainsRe(err, regex)
1327
1369
        return out, err
1328
1370
 
1329
 
 
1330
1371
    def run_bzr_decode(self, *args, **kwargs):
1331
1372
        if 'encoding' in kwargs:
1332
1373
            encoding = kwargs['encoding']
1336
1377
 
1337
1378
    def run_bzr_error(self, error_regexes, *args, **kwargs):
1338
1379
        """Run bzr, and check that stderr contains the supplied regexes
1339
 
        
1340
 
        :param error_regexes: Sequence of regular expressions which 
 
1380
 
 
1381
        :param error_regexes: Sequence of regular expressions which
1341
1382
            must each be found in the error output. The relative ordering
1342
1383
            is not enforced.
1343
1384
        :param args: command-line arguments for bzr
1344
1385
        :param kwargs: Keyword arguments which are interpreted by run_bzr
1345
1386
            This function changes the default value of retcode to be 3,
1346
1387
            since in most cases this is run when you expect bzr to fail.
1347
 
        :return: (out, err) The actual output of running the command (in case you
1348
 
                 want to do more inspection)
1349
 
 
1350
 
        Examples of use:
 
1388
 
 
1389
        :return: (out, err) The actual output of running the command (in case
 
1390
            you want to do more inspection)
 
1391
 
 
1392
        Examples of use::
 
1393
 
1351
1394
            # Make sure that commit is failing because there is nothing to do
1352
1395
            self.run_bzr_error(['no changes to commit'],
1353
1396
                               'commit', '-m', 'my commit comment')
1358
1401
                               'commit', '--strict', '-m', 'my commit comment')
1359
1402
        """
1360
1403
        kwargs.setdefault('retcode', 3)
1361
 
        out, err = self.run_bzr(error_regexes=error_regexes, *args, **kwargs)
 
1404
        kwargs['error_regexes'] = error_regexes
 
1405
        out, err = self.run_bzr(*args, **kwargs)
1362
1406
        return out, err
1363
1407
 
1364
1408
    def run_bzr_subprocess(self, *args, **kwargs):
1370
1414
        handling, or early startup code, etc.  Subprocess code can't be 
1371
1415
        profiled or debugged so easily.
1372
1416
 
1373
 
        :param retcode: The status code that is expected.  Defaults to 0.  If
 
1417
        :keyword retcode: The status code that is expected.  Defaults to 0.  If
1374
1418
            None is supplied, the status code is not checked.
1375
 
        :param env_changes: A dictionary which lists changes to environment
 
1419
        :keyword env_changes: A dictionary which lists changes to environment
1376
1420
            variables. A value of None will unset the env variable.
1377
1421
            The values must be strings. The change will only occur in the
1378
1422
            child, so you don't need to fix the environment after running.
1379
 
        :param universal_newlines: Convert CRLF => LF
1380
 
        :param allow_plugins: By default the subprocess is run with
 
1423
        :keyword universal_newlines: Convert CRLF => LF
 
1424
        :keyword allow_plugins: By default the subprocess is run with
1381
1425
            --no-plugins to ensure test reproducibility. Also, it is possible
1382
1426
            for system-wide plugins to create unexpected output on stderr,
1383
1427
            which can cause unnecessary test failures.
1407
1451
        profiled or debugged so easily.
1408
1452
 
1409
1453
        :param process_args: a list of arguments to pass to the bzr executable,
1410
 
            for example `['--version']`.
 
1454
            for example ``['--version']``.
1411
1455
        :param env_changes: A dictionary which lists changes to environment
1412
1456
            variables. A value of None will unset the env variable.
1413
1457
            The values must be strings. The change will only occur in the
1511
1555
        shape = list(shape)             # copy
1512
1556
        for path, ie in inv.entries():
1513
1557
            name = path.replace('\\', '/')
1514
 
            if ie.kind == 'dir':
 
1558
            if ie.kind == 'directory':
1515
1559
                name = name + '/'
1516
1560
            if name in shape:
1517
1561
                shape.remove(name)
1554
1598
            sys.stderr = real_stderr
1555
1599
            sys.stdin = real_stdin
1556
1600
 
1557
 
    @symbol_versioning.deprecated_method(symbol_versioning.zero_eleven)
1558
 
    def merge(self, branch_from, wt_to):
1559
 
        """A helper for tests to do a ui-less merge.
1560
 
 
1561
 
        This should move to the main library when someone has time to integrate
1562
 
        it in.
1563
 
        """
1564
 
        # minimal ui-less merge.
1565
 
        wt_to.branch.fetch(branch_from)
1566
 
        base_rev = common_ancestor(branch_from.last_revision(),
1567
 
                                   wt_to.branch.last_revision(),
1568
 
                                   wt_to.branch.repository)
1569
 
        merge_inner(wt_to.branch, branch_from.basis_tree(),
1570
 
                    wt_to.branch.repository.revision_tree(base_rev),
1571
 
                    this_tree=wt_to)
1572
 
        wt_to.add_parent_tree_id(branch_from.last_revision())
1573
 
 
1574
1601
    def reduceLockdirTimeout(self):
1575
1602
        """Reduce the default lock timeout for the duration of the test, so that
1576
1603
        if LockContention occurs during a test, it does so quickly.
1583
1610
        self.addCleanup(resetTimeout)
1584
1611
        bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS = 0
1585
1612
 
1586
 
BzrTestBase = TestCase
1587
 
 
1588
1613
 
1589
1614
class TestCaseWithMemoryTransport(TestCase):
1590
1615
    """Common test class for tests that do not need disk resources.
1600
1625
    file defaults for the transport in tests, nor does it obey the command line
1601
1626
    override, so tests that accidentally write to the common directory should
1602
1627
    be rare.
 
1628
 
 
1629
    :cvar TEST_ROOT: Directory containing all temporary directories, plus
 
1630
    a .bzr directory that stops us ascending higher into the filesystem.
1603
1631
    """
1604
1632
 
1605
1633
    TEST_ROOT = None
1606
1634
    _TEST_NAME = 'test'
1607
1635
 
1608
 
 
1609
1636
    def __init__(self, methodName='runTest'):
1610
1637
        # allow test parameterisation after test construction and before test
1611
1638
        # execution. Variables that the parameteriser sets need to be 
1616
1643
        self.transport_readonly_server = None
1617
1644
        self.__vfs_server = None
1618
1645
 
1619
 
    def get_transport(self):
1620
 
        """Return a writeable transport for the test scratch space"""
1621
 
        t = get_transport(self.get_url())
 
1646
    def get_transport(self, relpath=None):
 
1647
        """Return a writeable transport.
 
1648
 
 
1649
        This transport is for the test scratch space relative to
 
1650
        "self._test_root""
 
1651
        
 
1652
        :param relpath: a path relative to the base url.
 
1653
        """
 
1654
        t = get_transport(self.get_url(relpath))
1622
1655
        self.assertFalse(t.is_readonly())
1623
1656
        return t
1624
1657
 
1625
 
    def get_readonly_transport(self):
 
1658
    def get_readonly_transport(self, relpath=None):
1626
1659
        """Return a readonly transport for the test scratch space
1627
1660
        
1628
1661
        This can be used to test that operations which should only need
1629
1662
        readonly access in fact do not try to write.
 
1663
 
 
1664
        :param relpath: a path relative to the base url.
1630
1665
        """
1631
 
        t = get_transport(self.get_readonly_url())
 
1666
        t = get_transport(self.get_readonly_url(relpath))
1632
1667
        self.assertTrue(t.is_readonly())
1633
1668
        return t
1634
1669
 
1665
1700
        These should only be downwards relative, not upwards.
1666
1701
        """
1667
1702
        base = self.get_readonly_server().get_url()
1668
 
        if relpath is not None:
1669
 
            if not base.endswith('/'):
1670
 
                base = base + '/'
1671
 
            base = base + relpath
1672
 
        return base
 
1703
        return self._adjust_url(base, relpath)
1673
1704
 
1674
1705
    def get_vfs_only_server(self):
1675
1706
        """Get the vfs only read/write server instance.
1750
1781
        capabilities of the local filesystem, but it might actually be a
1751
1782
        MemoryTransport or some other similar virtual filesystem.
1752
1783
 
1753
 
        This is the backing transport (if any) of the server returned by 
 
1784
        This is the backing transport (if any) of the server returned by
1754
1785
        get_url and get_readonly_url.
1755
1786
 
1756
1787
        :param relpath: provides for clients to get a path relative to the base
1757
1788
            url.  These should only be downwards relative, not upwards.
 
1789
        :return: A URL
1758
1790
        """
1759
1791
        base = self.get_vfs_only_server().get_url()
1760
1792
        return self._adjust_url(base, relpath)
1762
1794
    def _make_test_root(self):
1763
1795
        if TestCaseWithMemoryTransport.TEST_ROOT is not None:
1764
1796
            return
1765
 
        i = 0
1766
 
        while True:
1767
 
            root = u'test%04d.tmp' % i
1768
 
            try:
1769
 
                os.mkdir(root)
1770
 
            except OSError, e:
1771
 
                if e.errno == errno.EEXIST:
1772
 
                    i += 1
1773
 
                    continue
1774
 
                else:
1775
 
                    raise
1776
 
            # successfully created
1777
 
            TestCaseWithMemoryTransport.TEST_ROOT = osutils.abspath(root)
1778
 
            break
 
1797
        root = tempfile.mkdtemp(prefix='testbzr-', suffix='.tmp')
 
1798
        TestCaseWithMemoryTransport.TEST_ROOT = root
 
1799
        
1779
1800
        # make a fake bzr directory there to prevent any tests propagating
1780
1801
        # up onto the source directory's real branch
1781
 
        bzrdir.BzrDir.create_standalone_workingtree(
1782
 
            TestCaseWithMemoryTransport.TEST_ROOT)
 
1802
        bzrdir.BzrDir.create_standalone_workingtree(root)
 
1803
 
 
1804
        # The same directory is used by all tests, and we're not specifically
 
1805
        # told when all tests are finished.  This will do.
 
1806
        atexit.register(_rmtree_temp_dir, root)
1783
1807
 
1784
1808
    def makeAndChdirToTestDir(self):
1785
1809
        """Create a temporary directories for this one test.
1859
1883
    All test cases create their own directory within that.  If the
1860
1884
    tests complete successfully, the directory is removed.
1861
1885
 
1862
 
    InTempDir is an old alias for FunctionalTestCase.
 
1886
    :ivar test_base_dir: The path of the top-level directory for this 
 
1887
    test, which contains a home directory and a work directory.
 
1888
 
 
1889
    :ivar test_home_dir: An initially empty directory under test_base_dir
 
1890
    which is used as $HOME for this test.
 
1891
 
 
1892
    :ivar test_dir: A directory under test_base_dir used as the current
 
1893
    directory when the test proper is run.
1863
1894
    """
1864
1895
 
1865
1896
    OVERRIDE_PYTHON = 'python'
1879
1910
        For TestCaseInTempDir we create a temporary directory based on the test
1880
1911
        name and then create two subdirs - test and home under it.
1881
1912
        """
1882
 
        if self.use_numbered_dirs:  # strongly recommended on Windows
1883
 
                                    # due the path length limitation (260 ch.)
1884
 
            candidate_dir = '%s/%dK/%05d' % (self.TEST_ROOT,
1885
 
                                             int(self.number/1000),
1886
 
                                             self.number)
1887
 
            os.makedirs(candidate_dir)
1888
 
            self.test_home_dir = candidate_dir + '/home'
1889
 
            os.mkdir(self.test_home_dir)
1890
 
            self.test_dir = candidate_dir + '/work'
1891
 
            os.mkdir(self.test_dir)
1892
 
            os.chdir(self.test_dir)
1893
 
            # put name of test inside
1894
 
            f = file(candidate_dir + '/name', 'w')
 
1913
        # create a directory within the top level test directory
 
1914
        candidate_dir = tempfile.mkdtemp(dir=self.TEST_ROOT)
 
1915
        # now create test and home directories within this dir
 
1916
        self.test_base_dir = candidate_dir
 
1917
        self.test_home_dir = self.test_base_dir + '/home'
 
1918
        os.mkdir(self.test_home_dir)
 
1919
        self.test_dir = self.test_base_dir + '/work'
 
1920
        os.mkdir(self.test_dir)
 
1921
        os.chdir(self.test_dir)
 
1922
        # put name of test inside
 
1923
        f = file(self.test_base_dir + '/name', 'w')
 
1924
        try:
1895
1925
            f.write(self.id())
 
1926
        finally:
1896
1927
            f.close()
1897
 
            return
1898
 
        # Else NAMED DIRS
1899
 
        # shorten the name, to avoid test failures due to path length
1900
 
        short_id = self.id().replace('bzrlib.tests.', '') \
1901
 
                   .replace('__main__.', '')[-100:]
1902
 
        # it's possible the same test class is run several times for
1903
 
        # parameterized tests, so make sure the names don't collide.  
1904
 
        i = 0
1905
 
        while True:
1906
 
            if i > 0:
1907
 
                candidate_dir = '%s/%s.%d' % (self.TEST_ROOT, short_id, i)
1908
 
            else:
1909
 
                candidate_dir = '%s/%s' % (self.TEST_ROOT, short_id)
1910
 
            if os.path.exists(candidate_dir):
1911
 
                i = i + 1
1912
 
                continue
1913
 
            else:
1914
 
                os.mkdir(candidate_dir)
1915
 
                self.test_home_dir = candidate_dir + '/home'
1916
 
                os.mkdir(self.test_home_dir)
1917
 
                self.test_dir = candidate_dir + '/work'
1918
 
                os.mkdir(self.test_dir)
1919
 
                os.chdir(self.test_dir)
1920
 
                break
 
1928
        self.addCleanup(self.deleteTestDir)
 
1929
 
 
1930
    def deleteTestDir(self):
 
1931
        os.chdir(self.TEST_ROOT)
 
1932
        _rmtree_temp_dir(self.test_base_dir)
1921
1933
 
1922
1934
    def build_tree(self, shape, line_endings='binary', transport=None):
1923
1935
        """Build a test tree according to a pattern.
1928
1940
        This assumes that all the elements in the tree being built are new.
1929
1941
 
1930
1942
        This doesn't add anything to a branch.
 
1943
 
1931
1944
        :param line_endings: Either 'binary' or 'native'
1932
 
                             in binary mode, exact contents are written
1933
 
                             in native mode, the line endings match the
1934
 
                             default platform endings.
1935
 
 
1936
 
        :param transport: A transport to write to, for building trees on 
1937
 
                          VFS's. If the transport is readonly or None,
1938
 
                          "." is opened automatically.
 
1945
            in binary mode, exact contents are written in native mode, the
 
1946
            line endings match the default platform endings.
 
1947
        :param transport: A transport to write to, for building trees on VFS's.
 
1948
            If the transport is readonly or None, "." is opened automatically.
 
1949
        :return: None
1939
1950
        """
1940
1951
        # It's OK to just create them using forward slashes on windows.
1941
1952
        if transport is None or transport.is_readonly():
2159
2170
 
2160
2171
 
2161
2172
def run_suite(suite, name='test', verbose=False, pattern=".*",
2162
 
              stop_on_failure=False, keep_output=False,
 
2173
              stop_on_failure=False,
2163
2174
              transport=None, lsprof_timed=None, bench_history=None,
2164
2175
              matching_tests_first=None,
2165
2176
              numbered_dirs=None,
2179
2190
    runner = TextTestRunner(stream=sys.stdout,
2180
2191
                            descriptions=0,
2181
2192
                            verbosity=verbosity,
2182
 
                            keep_output=keep_output,
2183
2193
                            bench_history=bench_history,
2184
2194
                            use_numbered_dirs=use_numbered_dirs,
2185
2195
                            list_only=list_only,
2214
2224
 
2215
2225
 
2216
2226
def selftest(verbose=False, pattern=".*", stop_on_failure=True,
2217
 
             keep_output=False,
2218
2227
             transport=None,
2219
2228
             test_suite_factory=None,
2220
2229
             lsprof_timed=None,
2242
2251
        else:
2243
2252
            suite = test_suite_factory()
2244
2253
        return run_suite(suite, 'testbzr', verbose=verbose, pattern=pattern,
2245
 
                     stop_on_failure=stop_on_failure, keep_output=keep_output,
 
2254
                     stop_on_failure=stop_on_failure,
2246
2255
                     transport=transport,
2247
2256
                     lsprof_timed=lsprof_timed,
2248
2257
                     bench_history=bench_history,
2269
2278
                   'bzrlib.tests.test_atomicfile',
2270
2279
                   'bzrlib.tests.test_bad_files',
2271
2280
                   'bzrlib.tests.test_branch',
 
2281
                   'bzrlib.tests.test_branchbuilder',
2272
2282
                   'bzrlib.tests.test_bugtracker',
2273
2283
                   'bzrlib.tests.test_bundle',
2274
2284
                   'bzrlib.tests.test_bzrdir',
2278
2288
                   'bzrlib.tests.test_commit_merge',
2279
2289
                   'bzrlib.tests.test_config',
2280
2290
                   'bzrlib.tests.test_conflicts',
 
2291
                   'bzrlib.tests.test_pack',
 
2292
                   'bzrlib.tests.test_counted_lock',
2281
2293
                   'bzrlib.tests.test_decorators',
2282
2294
                   'bzrlib.tests.test_delta',
 
2295
                   'bzrlib.tests.test_deprecated_graph',
2283
2296
                   'bzrlib.tests.test_diff',
2284
2297
                   'bzrlib.tests.test_dirstate',
2285
2298
                   'bzrlib.tests.test_errors',
2294
2307
                   'bzrlib.tests.test_graph',
2295
2308
                   'bzrlib.tests.test_hashcache',
2296
2309
                   'bzrlib.tests.test_help',
 
2310
                   'bzrlib.tests.test_hooks',
2297
2311
                   'bzrlib.tests.test_http',
2298
2312
                   'bzrlib.tests.test_http_response',
2299
2313
                   'bzrlib.tests.test_https_ca_bundle',
2300
2314
                   'bzrlib.tests.test_identitymap',
2301
2315
                   'bzrlib.tests.test_ignores',
 
2316
                   'bzrlib.tests.test_info',
2302
2317
                   'bzrlib.tests.test_inv',
2303
2318
                   'bzrlib.tests.test_knit',
2304
2319
                   'bzrlib.tests.test_lazy_import',
2306
2321
                   'bzrlib.tests.test_lockdir',
2307
2322
                   'bzrlib.tests.test_lockable_files',
2308
2323
                   'bzrlib.tests.test_log',
 
2324
                   'bzrlib.tests.test_lsprof',
2309
2325
                   'bzrlib.tests.test_memorytree',
2310
2326
                   'bzrlib.tests.test_merge',
2311
2327
                   'bzrlib.tests.test_merge3',
2338
2354
                   'bzrlib.tests.test_smart',
2339
2355
                   'bzrlib.tests.test_smart_add',
2340
2356
                   'bzrlib.tests.test_smart_transport',
 
2357
                   'bzrlib.tests.test_smtp_connection',
2341
2358
                   'bzrlib.tests.test_source',
2342
2359
                   'bzrlib.tests.test_ssh_transport',
2343
2360
                   'bzrlib.tests.test_status',
2378
2395
    suite = TestUtil.TestSuite()
2379
2396
    loader = TestUtil.TestLoader()
2380
2397
    suite.addTest(loader.loadTestsFromModuleNames(testmod_names))
2381
 
    from bzrlib.transport import TransportTestProviderAdapter
 
2398
    from bzrlib.tests.test_transport_implementations import TransportTestProviderAdapter
2382
2399
    adapter = TransportTestProviderAdapter()
2383
2400
    adapt_modules(test_transport_implementations, adapter, loader, suite)
2384
2401
    for package in packages_to_test():
2417
2434
 
2418
2435
 
2419
2436
def _rmtree_temp_dir(dirname):
 
2437
    # If LANG=C we probably have created some bogus paths
 
2438
    # which rmtree(unicode) will fail to delete
 
2439
    # so make sure we are using rmtree(str) to delete everything
 
2440
    # except on win32, where rmtree(str) will fail
 
2441
    # since it doesn't have the property of byte-stream paths
 
2442
    # (they are either ascii or mbcs)
 
2443
    if sys.platform == 'win32':
 
2444
        # make sure we are using the unicode win32 api
 
2445
        dirname = unicode(dirname)
 
2446
    else:
 
2447
        dirname = dirname.encode(sys.getfilesystemencoding())
2420
2448
    try:
2421
2449
        osutils.rmtree(dirname)
2422
2450
    except OSError, e:
2472
2500
        if getattr(self, 'feature_name', None):
2473
2501
            return self.feature_name()
2474
2502
        return self.__class__.__name__
 
2503
 
 
2504
 
 
2505
class TestScenarioApplier(object):
 
2506
    """A tool to apply scenarios to tests."""
 
2507
 
 
2508
    def adapt(self, test):
 
2509
        """Return a TestSuite containing a copy of test for each scenario."""
 
2510
        result = unittest.TestSuite()
 
2511
        for scenario in self.scenarios:
 
2512
            result.addTest(self.adapt_test_to_scenario(test, scenario))
 
2513
        return result
 
2514
 
 
2515
    def adapt_test_to_scenario(self, test, scenario):
 
2516
        """Copy test and apply scenario to it.
 
2517
 
 
2518
        :param test: A test to adapt.
 
2519
        :param scenario: A tuple describing the scenarion.
 
2520
            The first element of the tuple is the new test id.
 
2521
            The second element is a dict containing attributes to set on the
 
2522
            test.
 
2523
        :return: The adapted test.
 
2524
        """
 
2525
        from copy import deepcopy
 
2526
        new_test = deepcopy(test)
 
2527
        for name, value in scenario[1].items():
 
2528
            setattr(new_test, name, value)
 
2529
        new_id = "%s(%s)" % (new_test.id(), scenario[0])
 
2530
        new_test.id = lambda: new_id
 
2531
        return new_test