~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Robert Collins
  • Date: 2006-09-18 05:35:44 UTC
  • mto: (1986.4.4 test_ancestry.py)
  • mto: This revision was merged to the branch mainline in revision 2059.
  • Revision ID: robertc@robertcollins.net-20060918053544-531ddf7fd2ae877b
New test base class TestCaseWithMemoryTransport offers memory-only
testing facilities: its not suitable for tests that need to mutate disk
state, but most tests should not need that and should be converted to
TestCaseWithMemoryTransport. (Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
70
70
from bzrlib.transport import get_transport
71
71
import bzrlib.transport
72
72
from bzrlib.transport.local import LocalRelpathServer
 
73
from bzrlib.transport.memory import MemoryServer
73
74
from bzrlib.transport.readonly import ReadonlyServer
74
75
from bzrlib.trace import mutter
75
76
from bzrlib.tests import TestUtil
382
383
        # This is still a little bogus, 
383
384
        # but only a little. Folk not using our testrunner will
384
385
        # have to delete their temp directories themselves.
385
 
        test_root = TestCaseInTempDir.TEST_ROOT
 
386
        test_root = TestCaseWithMemoryTransport.TEST_ROOT
386
387
        if result.wasSuccessful() or not self.keep_output:
387
388
            if test_root is not None:
388
389
                # If LANG=C we probably have created some bogus paths
406
407
                self.stream.writeln(
407
408
                    "Failed tests working directories are in '%s'\n" %
408
409
                    test_root)
409
 
        TestCaseInTempDir.TEST_ROOT = None
 
410
        TestCaseWithMemoryTransport.TEST_ROOT = None
410
411
        if self.pb is not None:
411
412
            self.pb.clear()
412
413
        return result
1048
1049
 
1049
1050
BzrTestBase = TestCase
1050
1051
 
1051
 
     
1052
 
class TestCaseInTempDir(TestCase):
1053
 
    """Derived class that runs a test within a temporary directory.
1054
 
 
1055
 
    This is useful for tests that need to create a branch, etc.
1056
 
 
1057
 
    The directory is created in a slightly complex way: for each
1058
 
    Python invocation, a new temporary top-level directory is created.
1059
 
    All test cases create their own directory within that.  If the
1060
 
    tests complete successfully, the directory is removed.
1061
 
 
1062
 
    InTempDir is an old alias for FunctionalTestCase.
 
1052
 
 
1053
class TestCaseWithMemoryTransport(TestCase):
 
1054
    """Common test class for tests that do not need disk resources.
 
1055
 
 
1056
    Tests that need disk resources should derive from TestCaseWithTransport.
 
1057
 
 
1058
    TestCaseWithMemoryTransport sets the TEST_ROOT variable for all bzr tests.
 
1059
 
 
1060
    For TestCaseWithMemoryTransport the test_home_dir is set to the name of
 
1061
    a directory which does not exist. This serves to help ensure test isolation
 
1062
    is preserved. test_dir is set to the TEST_ROOT, as is cwd, because they
 
1063
    must exist. However, TestCaseWithMemoryTransport does not offer local
 
1064
    file defaults for the transport in tests, nor does it obey the command line
 
1065
    override, so tests that accidentally write to the common directory should
 
1066
    be rare.
1063
1067
    """
1064
1068
 
1065
1069
    TEST_ROOT = None
1066
1070
    _TEST_NAME = 'test'
1067
 
    OVERRIDE_PYTHON = 'python'
1068
 
 
1069
 
    def check_file_contents(self, filename, expect):
1070
 
        self.log("check contents of file %s" % filename)
1071
 
        contents = file(filename, 'r').read()
1072
 
        if contents != expect:
1073
 
            self.log("expected: %r" % expect)
1074
 
            self.log("actually: %r" % contents)
1075
 
            self.fail("contents of %s not as expected" % filename)
 
1071
 
 
1072
    def failUnlessExists(self, path):
 
1073
        """Fail unless path, which may be abs or relative, exists."""
 
1074
        self.failUnless(osutils.lexists(path))
 
1075
 
 
1076
    def failIfExists(self, path):
 
1077
        """Fail if path, which may be abs or relative, exists."""
 
1078
        self.failIf(osutils.lexists(path))
 
1079
        
 
1080
    def get_transport(self):
 
1081
        """Return a writeable transport for the test scratch space"""
 
1082
        t = get_transport(self.get_url())
 
1083
        self.assertFalse(t.is_readonly())
 
1084
        return t
 
1085
 
 
1086
    def get_readonly_transport(self):
 
1087
        """Return a readonly transport for the test scratch space
 
1088
        
 
1089
        This can be used to test that operations which should only need
 
1090
        readonly access in fact do not try to write.
 
1091
        """
 
1092
        t = get_transport(self.get_readonly_url())
 
1093
        self.assertTrue(t.is_readonly())
 
1094
        return t
 
1095
 
 
1096
    def get_readonly_server(self):
 
1097
        """Get the server instance for the readonly transport
 
1098
 
 
1099
        This is useful for some tests with specific servers to do diagnostics.
 
1100
        """
 
1101
        if self.__readonly_server is None:
 
1102
            if self.transport_readonly_server is None:
 
1103
                # readonly decorator requested
 
1104
                # bring up the server
 
1105
                self.get_url()
 
1106
                self.__readonly_server = ReadonlyServer()
 
1107
                self.__readonly_server.setUp(self.__server)
 
1108
            else:
 
1109
                self.__readonly_server = self.transport_readonly_server()
 
1110
                self.__readonly_server.setUp()
 
1111
            self.addCleanup(self.__readonly_server.tearDown)
 
1112
        return self.__readonly_server
 
1113
 
 
1114
    def get_readonly_url(self, relpath=None):
 
1115
        """Get a URL for the readonly transport.
 
1116
 
 
1117
        This will either be backed by '.' or a decorator to the transport 
 
1118
        used by self.get_url()
 
1119
        relpath provides for clients to get a path relative to the base url.
 
1120
        These should only be downwards relative, not upwards.
 
1121
        """
 
1122
        base = self.get_readonly_server().get_url()
 
1123
        if relpath is not None:
 
1124
            if not base.endswith('/'):
 
1125
                base = base + '/'
 
1126
            base = base + relpath
 
1127
        return base
 
1128
 
 
1129
    def get_server(self):
 
1130
        """Get the read/write server instance.
 
1131
 
 
1132
        This is useful for some tests with specific servers that need
 
1133
        diagnostics.
 
1134
 
 
1135
        For TestCaseWithMemoryTransport this is always a MemoryServer, and there
 
1136
        is no means to override it.
 
1137
        """
 
1138
        if self.__server is None:
 
1139
            self.__server = MemoryServer()
 
1140
            self.__server.setUp()
 
1141
            self.addCleanup(self.__server.tearDown)
 
1142
        return self.__server
 
1143
 
 
1144
    def get_url(self, relpath=None):
 
1145
        """Get a URL (or maybe a path) for the readwrite transport.
 
1146
 
 
1147
        This will either be backed by '.' or to an equivalent non-file based
 
1148
        facility.
 
1149
        relpath provides for clients to get a path relative to the base url.
 
1150
        These should only be downwards relative, not upwards.
 
1151
        """
 
1152
        base = self.get_server().get_url()
 
1153
        if relpath is not None and relpath != '.':
 
1154
            if not base.endswith('/'):
 
1155
                base = base + '/'
 
1156
            # XXX: Really base should be a url; we did after all call
 
1157
            # get_url()!  But sometimes it's just a path (from
 
1158
            # LocalAbspathServer), and it'd be wrong to append urlescaped data
 
1159
            # to a non-escaped local path.
 
1160
            if base.startswith('./') or base.startswith('/'):
 
1161
                base += relpath
 
1162
            else:
 
1163
                base += urlutils.escape(relpath)
 
1164
        return base
1076
1165
 
1077
1166
    def _make_test_root(self):
1078
 
        if TestCaseInTempDir.TEST_ROOT is not None:
 
1167
        if TestCaseWithMemoryTransport.TEST_ROOT is not None:
1079
1168
            return
1080
1169
        i = 0
1081
1170
        while True:
1089
1178
                else:
1090
1179
                    raise
1091
1180
            # successfully created
1092
 
            TestCaseInTempDir.TEST_ROOT = osutils.abspath(root)
 
1181
            TestCaseWithMemoryTransport.TEST_ROOT = osutils.abspath(root)
1093
1182
            break
1094
1183
        # make a fake bzr directory there to prevent any tests propagating
1095
1184
        # up onto the source directory's real branch
1096
 
        bzrdir.BzrDir.create_standalone_workingtree(TestCaseInTempDir.TEST_ROOT)
1097
 
 
 
1185
        bzrdir.BzrDir.create_standalone_workingtree(
 
1186
            TestCaseWithMemoryTransport.TEST_ROOT)
 
1187
 
 
1188
    def makeAndChdirToTestDir(self):
 
1189
        """Create a temporary directories for this one test.
 
1190
        
 
1191
        This must set self.test_home_dir and self.test_dir and chdir to
 
1192
        self.test_dir.
 
1193
        
 
1194
        For TestCaseWithMemoryTransport we chdir to the TEST_ROOT for this test.
 
1195
        """
 
1196
        os.chdir(TestCaseWithMemoryTransport.TEST_ROOT)
 
1197
        self.test_dir = TestCaseWithMemoryTransport.TEST_ROOT
 
1198
        self.test_home_dir = self.test_dir + "/MemoryTransportMissingHomeDir"
 
1199
        
 
1200
    def make_branch(self, relpath, format=None):
 
1201
        """Create a branch on the transport at relpath."""
 
1202
        repo = self.make_repository(relpath, format=format)
 
1203
        return repo.bzrdir.create_branch()
 
1204
 
 
1205
    def make_bzrdir(self, relpath, format=None):
 
1206
        try:
 
1207
            # might be a relative or absolute path
 
1208
            maybe_a_url = self.get_url(relpath)
 
1209
            segments = maybe_a_url.rsplit('/', 1)
 
1210
            t = get_transport(maybe_a_url)
 
1211
            if len(segments) > 1 and segments[-1] not in ('', '.'):
 
1212
                try:
 
1213
                    t.mkdir('.')
 
1214
                except errors.FileExists:
 
1215
                    pass
 
1216
            if format is None:
 
1217
                format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
 
1218
            return format.initialize_on_transport(t)
 
1219
        except errors.UninitializableFormat:
 
1220
            raise TestSkipped("Format %s is not initializable." % format)
 
1221
 
 
1222
    def make_repository(self, relpath, shared=False, format=None):
 
1223
        """Create a repository on our default transport at relpath."""
 
1224
        made_control = self.make_bzrdir(relpath, format=format)
 
1225
        return made_control.create_repository(shared=shared)
 
1226
 
 
1227
    def make_branch_and_memory_tree(self, relpath):
 
1228
        """Create a branch on the default transport and a MemoryTree for it."""
 
1229
        b = self.make_branch(relpath)
 
1230
        return memorytree.MemoryTree.create_on_branch(b)
 
1231
 
 
1232
    def overrideEnvironmentForTesting(self):
 
1233
        os.environ['HOME'] = self.test_home_dir
 
1234
        os.environ['APPDATA'] = self.test_home_dir
 
1235
        
1098
1236
    def setUp(self):
1099
 
        super(TestCaseInTempDir, self).setUp()
 
1237
        super(TestCaseWithMemoryTransport, self).setUp()
1100
1238
        self._make_test_root()
1101
1239
        _currentdir = os.getcwdu()
 
1240
        def _leaveDirectory():
 
1241
            os.chdir(_currentdir)
 
1242
        self.addCleanup(_leaveDirectory)
 
1243
        self.makeAndChdirToTestDir()
 
1244
        self.overrideEnvironmentForTesting()
 
1245
        self.__readonly_server = None
 
1246
        self.__server = None
 
1247
        self.transport_server = default_transport
 
1248
        self.transport_readonly_server = None
 
1249
 
 
1250
     
 
1251
class TestCaseInTempDir(TestCaseWithMemoryTransport):
 
1252
    """Derived class that runs a test within a temporary directory.
 
1253
 
 
1254
    This is useful for tests that need to create a branch, etc.
 
1255
 
 
1256
    The directory is created in a slightly complex way: for each
 
1257
    Python invocation, a new temporary top-level directory is created.
 
1258
    All test cases create their own directory within that.  If the
 
1259
    tests complete successfully, the directory is removed.
 
1260
 
 
1261
    InTempDir is an old alias for FunctionalTestCase.
 
1262
    """
 
1263
 
 
1264
    OVERRIDE_PYTHON = 'python'
 
1265
 
 
1266
    def check_file_contents(self, filename, expect):
 
1267
        self.log("check contents of file %s" % filename)
 
1268
        contents = file(filename, 'r').read()
 
1269
        if contents != expect:
 
1270
            self.log("expected: %r" % expect)
 
1271
            self.log("actually: %r" % contents)
 
1272
            self.fail("contents of %s not as expected" % filename)
 
1273
 
 
1274
    def makeAndChdirToTestDir(self):
 
1275
        """See TestCaseWithMemoryTransport.makeAndChdirToTestDir().
 
1276
        
 
1277
        For TestCaseInTempDir we create a temporary directory based on the test
 
1278
        name and then create two subdirs - test and home under it.
 
1279
        """
1102
1280
        # shorten the name, to avoid test failures due to path length
1103
1281
        short_id = self.id().replace('bzrlib.tests.', '') \
1104
1282
                   .replace('__main__.', '')[-100:]
1121
1299
                os.mkdir(self.test_dir)
1122
1300
                os.chdir(self.test_dir)
1123
1301
                break
1124
 
        os.environ['HOME'] = self.test_home_dir
1125
 
        os.environ['APPDATA'] = self.test_home_dir
1126
 
        def _leaveDirectory():
1127
 
            os.chdir(_currentdir)
1128
 
        self.addCleanup(_leaveDirectory)
1129
 
        
 
1302
 
1130
1303
    def build_tree(self, shape, line_endings='native', transport=None):
1131
1304
        """Build a test tree according to a pattern.
1132
1305
 
1173
1346
    def build_tree_contents(self, shape):
1174
1347
        build_tree_contents(shape)
1175
1348
 
1176
 
    def failUnlessExists(self, path):
1177
 
        """Fail unless path, which may be abs or relative, exists."""
1178
 
        self.failUnless(osutils.lexists(path))
1179
 
 
1180
 
    def failIfExists(self, path):
1181
 
        """Fail if path, which may be abs or relative, exists."""
1182
 
        self.failIf(osutils.lexists(path))
1183
 
        
1184
1349
    def assertFileEqual(self, content, path):
1185
1350
        """Fail if path does not contain 'content'."""
1186
1351
        self.failUnless(osutils.lexists(path))
1202
1367
    readwrite one must both define get_url() as resolving to os.getcwd().
1203
1368
    """
1204
1369
 
1205
 
    def __init__(self, methodName='testMethod'):
1206
 
        super(TestCaseWithTransport, self).__init__(methodName)
1207
 
        self.__readonly_server = None
1208
 
        self.__server = None
1209
 
        self.transport_server = default_transport
1210
 
        self.transport_readonly_server = None
1211
 
 
1212
 
    def get_readonly_url(self, relpath=None):
1213
 
        """Get a URL for the readonly transport.
1214
 
 
1215
 
        This will either be backed by '.' or a decorator to the transport 
1216
 
        used by self.get_url()
1217
 
        relpath provides for clients to get a path relative to the base url.
1218
 
        These should only be downwards relative, not upwards.
1219
 
        """
1220
 
        base = self.get_readonly_server().get_url()
1221
 
        if relpath is not None:
1222
 
            if not base.endswith('/'):
1223
 
                base = base + '/'
1224
 
            base = base + relpath
1225
 
        return base
1226
 
 
1227
 
    def get_readonly_server(self):
1228
 
        """Get the server instance for the readonly transport
1229
 
 
1230
 
        This is useful for some tests with specific servers to do diagnostics.
1231
 
        """
1232
 
        if self.__readonly_server is None:
1233
 
            if self.transport_readonly_server is None:
1234
 
                # readonly decorator requested
1235
 
                # bring up the server
1236
 
                self.get_url()
1237
 
                self.__readonly_server = ReadonlyServer()
1238
 
                self.__readonly_server.setUp(self.__server)
1239
 
            else:
1240
 
                self.__readonly_server = self.transport_readonly_server()
1241
 
                self.__readonly_server.setUp()
1242
 
            self.addCleanup(self.__readonly_server.tearDown)
1243
 
        return self.__readonly_server
1244
 
 
1245
1370
    def get_server(self):
1246
 
        """Get the read/write server instance.
 
1371
        """See TestCaseWithMemoryTransport.
1247
1372
 
1248
1373
        This is useful for some tests with specific servers that need
1249
1374
        diagnostics.
1254
1379
            self.addCleanup(self.__server.tearDown)
1255
1380
        return self.__server
1256
1381
 
1257
 
    def get_url(self, relpath=None):
1258
 
        """Get a URL (or maybe a path) for the readwrite transport.
1259
 
 
1260
 
        This will either be backed by '.' or to an equivalent non-file based
1261
 
        facility.
1262
 
        relpath provides for clients to get a path relative to the base url.
1263
 
        These should only be downwards relative, not upwards.
1264
 
        """
1265
 
        base = self.get_server().get_url()
1266
 
        if relpath is not None and relpath != '.':
1267
 
            if not base.endswith('/'):
1268
 
                base = base + '/'
1269
 
            # XXX: Really base should be a url; we did after all call
1270
 
            # get_url()!  But sometimes it's just a path (from
1271
 
            # LocalAbspathServer), and it'd be wrong to append urlescaped data
1272
 
            # to a non-escaped local path.
1273
 
            if base.startswith('./') or base.startswith('/'):
1274
 
                base += relpath
1275
 
            else:
1276
 
                base += urlutils.escape(relpath)
1277
 
        return base
1278
 
 
1279
 
    def get_transport(self):
1280
 
        """Return a writeable transport for the test scratch space"""
1281
 
        t = get_transport(self.get_url())
1282
 
        self.assertFalse(t.is_readonly())
1283
 
        return t
1284
 
 
1285
 
    def get_readonly_transport(self):
1286
 
        """Return a readonly transport for the test scratch space
1287
 
        
1288
 
        This can be used to test that operations which should only need
1289
 
        readonly access in fact do not try to write.
1290
 
        """
1291
 
        t = get_transport(self.get_readonly_url())
1292
 
        self.assertTrue(t.is_readonly())
1293
 
        return t
1294
 
 
1295
 
    def make_branch(self, relpath, format=None):
1296
 
        """Create a branch on the transport at relpath."""
1297
 
        repo = self.make_repository(relpath, format=format)
1298
 
        return repo.bzrdir.create_branch()
1299
 
 
1300
 
    def make_bzrdir(self, relpath, format=None):
1301
 
        try:
1302
 
            # might be a relative or absolute path
1303
 
            maybe_a_url = self.get_url(relpath)
1304
 
            segments = maybe_a_url.rsplit('/', 1)
1305
 
            t = get_transport(maybe_a_url)
1306
 
            if len(segments) > 1 and segments[-1] not in ('', '.'):
1307
 
                try:
1308
 
                    t.mkdir('.')
1309
 
                except errors.FileExists:
1310
 
                    pass
1311
 
            if format is None:
1312
 
                format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
1313
 
            return format.initialize_on_transport(t)
1314
 
        except errors.UninitializableFormat:
1315
 
            raise TestSkipped("Format %s is not initializable." % format)
1316
 
 
1317
 
    def make_repository(self, relpath, shared=False, format=None):
1318
 
        """Create a repository on our default transport at relpath."""
1319
 
        made_control = self.make_bzrdir(relpath, format=format)
1320
 
        return made_control.create_repository(shared=shared)
1321
 
 
1322
 
    def make_branch_and_memory_tree(self, relpath):
1323
 
        """Create a branch on the default transport and a MemoryTree for it."""
1324
 
        b = self.make_branch(relpath)
1325
 
        return memorytree.MemoryTree.create_on_branch(b)
1326
 
 
1327
1382
    def make_branch_and_tree(self, relpath, format=None):
1328
1383
        """Create a branch on the transport and a tree locally.
1329
1384
 
1371
1426
            self.fail("path %s is not a directory; has mode %#o"
1372
1427
                      % (relpath, mode))
1373
1428
 
 
1429
    def setUp(self):
 
1430
        super(TestCaseWithTransport, self).setUp()
 
1431
        self.__server = None
 
1432
        self.transport_server = default_transport
 
1433
 
1374
1434
 
1375
1435
class ChrootedTestCase(TestCaseWithTransport):
1376
1436
    """A support class that provides readonly urls outside the local namespace.
1402
1462
def run_suite(suite, name='test', verbose=False, pattern=".*",
1403
1463
              stop_on_failure=False, keep_output=False,
1404
1464
              transport=None, lsprof_timed=None, bench_history=None):
1405
 
    TestCaseInTempDir._TEST_NAME = name
1406
1465
    TestCase._gather_lsprof_in_benchmarks = lsprof_timed
1407
1466
    if verbose:
1408
1467
        verbosity = 2