~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
43
43
import time
44
44
 
45
45
 
 
46
from bzrlib import memorytree
46
47
import bzrlib.branch
47
48
import bzrlib.bzrdir as bzrdir
48
49
import bzrlib.commands
49
50
import bzrlib.bundle.serializer
50
51
import bzrlib.errors as errors
 
52
import bzrlib.export
51
53
import bzrlib.inventory
52
54
import bzrlib.iterablefile
53
55
import bzrlib.lockdir
69
71
from bzrlib.transport import get_transport
70
72
import bzrlib.transport
71
73
from bzrlib.transport.local import LocalRelpathServer
 
74
from bzrlib.transport.memory import MemoryServer
72
75
from bzrlib.transport.readonly import ReadonlyServer
73
76
from bzrlib.trace import mutter
74
77
from bzrlib.tests import TestUtil
84
87
 
85
88
MODULES_TO_TEST = []
86
89
MODULES_TO_DOCTEST = [
87
 
                      bzrlib.branch,
88
90
                      bzrlib.bundle.serializer,
89
 
                      bzrlib.commands,
90
91
                      bzrlib.errors,
 
92
                      bzrlib.export,
91
93
                      bzrlib.inventory,
92
94
                      bzrlib.iterablefile,
93
95
                      bzrlib.lockdir,
94
96
                      bzrlib.merge3,
95
97
                      bzrlib.option,
96
 
                      bzrlib.osutils,
97
 
                      bzrlib.store
 
98
                      bzrlib.store,
98
99
                      ]
99
100
 
100
101
 
150
151
            from bzrlib.version import _get_bzr_source_tree
151
152
            src_tree = _get_bzr_source_tree()
152
153
            if src_tree:
153
 
                revision_id = src_tree.last_revision()
 
154
                try:
 
155
                    revision_id = src_tree.get_parent_ids()[0]
 
156
                except IndexError:
 
157
                    # XXX: if this is a brand new tree, do the same as if there
 
158
                    # is no branch.
 
159
                    revision_id = ''
154
160
            else:
155
161
                # XXX: If there's no branch, what should we do?
156
162
                revision_id = ''
233
239
        if isinstance(err[1], TestSkipped):
234
240
            return self.addSkipped(test, err)    
235
241
        unittest.TestResult.addError(self, test, err)
 
242
        # We can only do this if we have one of our TestCases, not if
 
243
        # we have a doctest.
 
244
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
 
245
        if setKeepLogfile is not None:
 
246
            setKeepLogfile()
236
247
        self.extractBenchmarkTime(test)
237
248
        if self.showAll:
238
249
            self.stream.writeln("ERROR %s" % self._testTimeString())
249
260
 
250
261
    def addFailure(self, test, err):
251
262
        unittest.TestResult.addFailure(self, test, err)
 
263
        # We can only do this if we have one of our TestCases, not if
 
264
        # we have a doctest.
 
265
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
 
266
        if setKeepLogfile is not None:
 
267
            setKeepLogfile()
252
268
        self.extractBenchmarkTime(test)
253
269
        if self.showAll:
254
270
            self.stream.writeln(" FAIL %s" % self._testTimeString())
375
391
        # This is still a little bogus, 
376
392
        # but only a little. Folk not using our testrunner will
377
393
        # have to delete their temp directories themselves.
378
 
        test_root = TestCaseInTempDir.TEST_ROOT
 
394
        test_root = TestCaseWithMemoryTransport.TEST_ROOT
379
395
        if result.wasSuccessful() or not self.keep_output:
380
396
            if test_root is not None:
381
397
                # If LANG=C we probably have created some bogus paths
399
415
                self.stream.writeln(
400
416
                    "Failed tests working directories are in '%s'\n" %
401
417
                    test_root)
402
 
        TestCaseInTempDir.TEST_ROOT = None
 
418
        TestCaseWithMemoryTransport.TEST_ROOT = None
403
419
        if self.pb is not None:
404
420
            self.pb.clear()
405
421
        return result
475
491
 
476
492
    _log_file_name = None
477
493
    _log_contents = ''
 
494
    _keep_log_file = False
478
495
    # record lsprof data when performing benchmark calls.
479
496
    _gather_lsprof_in_benchmarks = False
480
497
 
655
672
    def _finishLogFile(self):
656
673
        """Finished with the log file.
657
674
 
658
 
        Read contents into memory, close, and delete.
 
675
        Close the file and delete it, unless setKeepLogfile was called.
659
676
        """
660
677
        if self._log_file is None:
661
678
            return
662
679
        bzrlib.trace.disable_test_log(self._log_nonce)
663
 
        self._log_file.seek(0)
664
 
        self._log_contents = self._log_file.read()
665
680
        self._log_file.close()
666
 
        os.remove(self._log_file_name)
667
 
        self._log_file = self._log_file_name = None
 
681
        self._log_file = None
 
682
        if not self._keep_log_file:
 
683
            os.remove(self._log_file_name)
 
684
            self._log_file_name = None
 
685
 
 
686
    def setKeepLogfile(self):
 
687
        """Make the logfile not be deleted when _finishLogFile is called."""
 
688
        self._keep_log_file = True
668
689
 
669
690
    def addCleanup(self, callable):
670
691
        """Arrange to run a callable when this case is torn down.
679
700
 
680
701
    def _cleanEnvironment(self):
681
702
        new_env = {
 
703
            'BZR_HOME': None, # Don't inherit BZR_HOME to all the tests.
682
704
            'HOME': os.getcwd(),
683
705
            'APPDATA': os.getcwd(),
684
706
            'BZR_EMAIL': None,
685
707
            'BZREMAIL': None, # may still be present in the environment
686
708
            'EMAIL': None,
 
709
            'BZR_PROGRESS_BAR': None,
687
710
        }
688
711
        self.__old_env = {}
689
712
        self.addCleanup(self._restoreEnvironment)
690
713
        for name, value in new_env.iteritems():
691
714
            self._captureVar(name, value)
692
715
 
693
 
 
694
716
    def _captureVar(self, name, newvalue):
695
 
        """Set an environment variable, preparing it to be reset when finished."""
696
 
        self.__old_env[name] = os.environ.get(name, None)
697
 
        if newvalue is None:
698
 
            if name in os.environ:
699
 
                del os.environ[name]
700
 
        else:
701
 
            os.environ[name] = newvalue
702
 
 
703
 
    @staticmethod
704
 
    def _restoreVar(name, value):
705
 
        if value is None:
706
 
            if name in os.environ:
707
 
                del os.environ[name]
708
 
        else:
709
 
            os.environ[name] = value
 
717
        """Set an environment variable, and reset it when finished."""
 
718
        self.__old_env[name] = osutils.set_or_unset_env(name, newvalue)
710
719
 
711
720
    def _restoreEnvironment(self):
712
721
        for name, value in self.__old_env.iteritems():
713
 
            self._restoreVar(name, value)
 
722
            osutils.set_or_unset_env(name, value)
714
723
 
715
724
    def tearDown(self):
716
725
        self._runCleanups()
751
760
    def log(self, *args):
752
761
        mutter(*args)
753
762
 
754
 
    def _get_log(self):
755
 
        """Return as a string the log for this test"""
756
 
        if self._log_file_name:
757
 
            return open(self._log_file_name).read()
758
 
        else:
 
763
    def _get_log(self, keep_log_file=False):
 
764
        """Return as a string the log for this test. If the file is still
 
765
        on disk and keep_log_file=False, delete the log file and store the
 
766
        content in self._log_contents."""
 
767
        # flush the log file, to get all content
 
768
        import bzrlib.trace
 
769
        bzrlib.trace._trace_file.flush()
 
770
        if self._log_contents:
759
771
            return self._log_contents
760
 
        # TODO: Delete the log after it's been read in
 
772
        if self._log_file_name is not None:
 
773
            logfile = open(self._log_file_name)
 
774
            try:
 
775
                log_contents = logfile.read()
 
776
            finally:
 
777
                logfile.close()
 
778
            if not keep_log_file:
 
779
                self._log_contents = log_contents
 
780
                os.remove(self._log_file_name)
 
781
            return log_contents
 
782
        else:
 
783
            return "DELETED log file to reduce memory footprint"
761
784
 
762
785
    def capture(self, cmd, retcode=0):
763
786
        """Shortcut that splits cmd into words, runs, and returns stdout"""
764
787
        return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
765
788
 
766
 
    def run_bzr_captured(self, argv, retcode=0, encoding=None, stdin=None):
 
789
    def run_bzr_captured(self, argv, retcode=0, encoding=None, stdin=None,
 
790
                         working_dir=None):
767
791
        """Invoke bzr and return (stdout, stderr).
768
792
 
769
793
        Useful for code that wants to check the contents of the
784
808
        :param retcode: expected return code, or None for don't-care.
785
809
        :param encoding: encoding for sys.stdout and sys.stderr
786
810
        :param stdin: A string to be used as stdin for the command.
 
811
        :param working_dir: Change to this directory before running
787
812
        """
788
813
        if encoding is None:
789
814
            encoding = bzrlib.user_encoding
805
830
            stdout=stdout,
806
831
            stderr=stderr)
807
832
        bzrlib.ui.ui_factory.stdin = stdin
 
833
 
 
834
        cwd = None
 
835
        if working_dir is not None:
 
836
            cwd = osutils.getcwd()
 
837
            os.chdir(working_dir)
 
838
 
808
839
        try:
809
840
            result = self.apply_redirected(stdin, stdout, stderr,
810
841
                                           bzrlib.commands.run_bzr_catch_errors,
812
843
        finally:
813
844
            logger.removeHandler(handler)
814
845
            bzrlib.ui.ui_factory = old_ui_factory
 
846
            if cwd is not None:
 
847
                os.chdir(cwd)
815
848
 
816
849
        out = stdout.getvalue()
817
850
        err = stderr.getvalue()
838
871
        retcode = kwargs.pop('retcode', 0)
839
872
        encoding = kwargs.pop('encoding', None)
840
873
        stdin = kwargs.pop('stdin', None)
841
 
        return self.run_bzr_captured(args, retcode=retcode, encoding=encoding, stdin=stdin)
 
874
        working_dir = kwargs.pop('working_dir', None)
 
875
        return self.run_bzr_captured(args, retcode=retcode, encoding=encoding,
 
876
                                     stdin=stdin, working_dir=working_dir)
842
877
 
843
878
    def run_bzr_decode(self, *args, **kwargs):
844
879
        if 'encoding' in kwargs:
891
926
            variables. A value of None will unset the env variable.
892
927
            The values must be strings. The change will only occur in the
893
928
            child, so you don't need to fix the environment after running.
 
929
        :param universal_newlines: Convert CRLF => LF
 
930
        :param allow_plugins: By default the subprocess is run with
 
931
            --no-plugins to ensure test reproducibility. Also, it is possible
 
932
            for system-wide plugins to create unexpected output on stderr,
 
933
            which can cause unnecessary test failures.
894
934
        """
895
935
        env_changes = kwargs.get('env_changes', {})
 
936
        working_dir = kwargs.get('working_dir', None)
 
937
        allow_plugins = kwargs.get('allow_plugins', False)
 
938
        process = self.start_bzr_subprocess(args, env_changes=env_changes,
 
939
                                            working_dir=working_dir,
 
940
                                            allow_plugins=allow_plugins)
 
941
        # We distinguish between retcode=None and retcode not passed.
 
942
        supplied_retcode = kwargs.get('retcode', 0)
 
943
        return self.finish_bzr_subprocess(process, retcode=supplied_retcode,
 
944
            universal_newlines=kwargs.get('universal_newlines', False),
 
945
            process_args=args)
 
946
 
 
947
    def start_bzr_subprocess(self, process_args, env_changes=None,
 
948
                             skip_if_plan_to_signal=False,
 
949
                             working_dir=None,
 
950
                             allow_plugins=False):
 
951
        """Start bzr in a subprocess for testing.
 
952
 
 
953
        This starts a new Python interpreter and runs bzr in there.
 
954
        This should only be used for tests that have a justifiable need for
 
955
        this isolation: e.g. they are testing startup time, or signal
 
956
        handling, or early startup code, etc.  Subprocess code can't be
 
957
        profiled or debugged so easily.
 
958
 
 
959
        :param process_args: a list of arguments to pass to the bzr executable,
 
960
            for example `['--version']`.
 
961
        :param env_changes: A dictionary which lists changes to environment
 
962
            variables. A value of None will unset the env variable.
 
963
            The values must be strings. The change will only occur in the
 
964
            child, so you don't need to fix the environment after running.
 
965
        :param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
 
966
            is not available.
 
967
        :param allow_plugins: If False (default) pass --no-plugins to bzr.
 
968
 
 
969
        :returns: Popen object for the started process.
 
970
        """
 
971
        if skip_if_plan_to_signal:
 
972
            if not getattr(os, 'kill', None):
 
973
                raise TestSkipped("os.kill not available.")
 
974
 
 
975
        if env_changes is None:
 
976
            env_changes = {}
 
977
        old_env = {}
 
978
 
896
979
        def cleanup_environment():
897
980
            for env_var, value in env_changes.iteritems():
898
 
                if value is None:
899
 
                    if env_var in os.environ:
900
 
                        del os.environ[env_var]
901
 
                else:
902
 
                    os.environ[env_var] = value
903
 
 
 
981
                old_env[env_var] = osutils.set_or_unset_env(env_var, value)
 
982
 
 
983
        def restore_environment():
 
984
            for env_var, value in old_env.iteritems():
 
985
                osutils.set_or_unset_env(env_var, value)
 
986
 
 
987
        bzr_path = self.get_bzr_path()
 
988
 
 
989
        cwd = None
 
990
        if working_dir is not None:
 
991
            cwd = osutils.getcwd()
 
992
            os.chdir(working_dir)
 
993
 
 
994
        try:
 
995
            # win32 subprocess doesn't support preexec_fn
 
996
            # so we will avoid using it on all platforms, just to
 
997
            # make sure the code path is used, and we don't break on win32
 
998
            cleanup_environment()
 
999
            command = [sys.executable, bzr_path]
 
1000
            if not allow_plugins:
 
1001
                command.append('--no-plugins')
 
1002
            command.extend(process_args)
 
1003
            process = self._popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE)
 
1004
        finally:
 
1005
            restore_environment()
 
1006
            if cwd is not None:
 
1007
                os.chdir(cwd)
 
1008
 
 
1009
        return process
 
1010
 
 
1011
    def _popen(self, *args, **kwargs):
 
1012
        """Place a call to Popen.
 
1013
 
 
1014
        Allows tests to override this method to intercept the calls made to
 
1015
        Popen for introspection.
 
1016
        """
 
1017
        return Popen(*args, **kwargs)
 
1018
 
 
1019
    def get_bzr_path(self):
 
1020
        """Return the path of the 'bzr' executable for this test suite."""
904
1021
        bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
905
 
        args = list(args)
906
 
        process = Popen([sys.executable, bzr_path]+args,
907
 
                         stdout=PIPE, stderr=PIPE,
908
 
                         preexec_fn=cleanup_environment)
909
 
        out = process.stdout.read()
910
 
        err = process.stderr.read()
911
 
        retcode = process.wait()
912
 
        supplied_retcode = kwargs.get('retcode', 0)
913
 
        if supplied_retcode is not None:
914
 
            assert supplied_retcode == retcode
 
1022
        if not os.path.isfile(bzr_path):
 
1023
            # We are probably installed. Assume sys.argv is the right file
 
1024
            bzr_path = sys.argv[0]
 
1025
        return bzr_path
 
1026
 
 
1027
    def finish_bzr_subprocess(self, process, retcode=0, send_signal=None,
 
1028
                              universal_newlines=False, process_args=None):
 
1029
        """Finish the execution of process.
 
1030
 
 
1031
        :param process: the Popen object returned from start_bzr_subprocess.
 
1032
        :param retcode: The status code that is expected.  Defaults to 0.  If
 
1033
            None is supplied, the status code is not checked.
 
1034
        :param send_signal: an optional signal to send to the process.
 
1035
        :param universal_newlines: Convert CRLF => LF
 
1036
        :returns: (stdout, stderr)
 
1037
        """
 
1038
        if send_signal is not None:
 
1039
            os.kill(process.pid, send_signal)
 
1040
        out, err = process.communicate()
 
1041
 
 
1042
        if universal_newlines:
 
1043
            out = out.replace('\r\n', '\n')
 
1044
            err = err.replace('\r\n', '\n')
 
1045
 
 
1046
        if retcode is not None and retcode != process.returncode:
 
1047
            if process_args is None:
 
1048
                process_args = "(unknown args)"
 
1049
            mutter('Output of bzr %s:\n%s', process_args, out)
 
1050
            mutter('Error for bzr %s:\n%s', process_args, err)
 
1051
            self.fail('Command bzr %s failed with retcode %s != %s'
 
1052
                      % (process_args, retcode, process.returncode))
915
1053
        return [out, err]
916
1054
 
917
1055
    def check_inventory_shape(self, inv, shape):
986
1124
 
987
1125
BzrTestBase = TestCase
988
1126
 
 
1127
 
 
1128
class TestCaseWithMemoryTransport(TestCase):
 
1129
    """Common test class for tests that do not need disk resources.
 
1130
 
 
1131
    Tests that need disk resources should derive from TestCaseWithTransport.
 
1132
 
 
1133
    TestCaseWithMemoryTransport sets the TEST_ROOT variable for all bzr tests.
 
1134
 
 
1135
    For TestCaseWithMemoryTransport the test_home_dir is set to the name of
 
1136
    a directory which does not exist. This serves to help ensure test isolation
 
1137
    is preserved. test_dir is set to the TEST_ROOT, as is cwd, because they
 
1138
    must exist. However, TestCaseWithMemoryTransport does not offer local
 
1139
    file defaults for the transport in tests, nor does it obey the command line
 
1140
    override, so tests that accidentally write to the common directory should
 
1141
    be rare.
 
1142
    """
 
1143
 
 
1144
    TEST_ROOT = None
 
1145
    _TEST_NAME = 'test'
 
1146
 
 
1147
 
 
1148
    def __init__(self, methodName='runTest'):
 
1149
        # allow test parameterisation after test construction and before test
 
1150
        # execution. Variables that the parameteriser sets need to be 
 
1151
        # ones that are not set by setUp, or setUp will trash them.
 
1152
        super(TestCaseWithMemoryTransport, self).__init__(methodName)
 
1153
        self.transport_server = default_transport
 
1154
        self.transport_readonly_server = None
 
1155
 
 
1156
    def failUnlessExists(self, path):
 
1157
        """Fail unless path, which may be abs or relative, exists."""
 
1158
        self.failUnless(osutils.lexists(path))
 
1159
 
 
1160
    def failIfExists(self, path):
 
1161
        """Fail if path, which may be abs or relative, exists."""
 
1162
        self.failIf(osutils.lexists(path))
 
1163
        
 
1164
    def get_transport(self):
 
1165
        """Return a writeable transport for the test scratch space"""
 
1166
        t = get_transport(self.get_url())
 
1167
        self.assertFalse(t.is_readonly())
 
1168
        return t
 
1169
 
 
1170
    def get_readonly_transport(self):
 
1171
        """Return a readonly transport for the test scratch space
 
1172
        
 
1173
        This can be used to test that operations which should only need
 
1174
        readonly access in fact do not try to write.
 
1175
        """
 
1176
        t = get_transport(self.get_readonly_url())
 
1177
        self.assertTrue(t.is_readonly())
 
1178
        return t
 
1179
 
 
1180
    def get_readonly_server(self):
 
1181
        """Get the server instance for the readonly transport
 
1182
 
 
1183
        This is useful for some tests with specific servers to do diagnostics.
 
1184
        """
 
1185
        if self.__readonly_server is None:
 
1186
            if self.transport_readonly_server is None:
 
1187
                # readonly decorator requested
 
1188
                # bring up the server
 
1189
                self.get_url()
 
1190
                self.__readonly_server = ReadonlyServer()
 
1191
                self.__readonly_server.setUp(self.__server)
 
1192
            else:
 
1193
                self.__readonly_server = self.transport_readonly_server()
 
1194
                self.__readonly_server.setUp()
 
1195
            self.addCleanup(self.__readonly_server.tearDown)
 
1196
        return self.__readonly_server
 
1197
 
 
1198
    def get_readonly_url(self, relpath=None):
 
1199
        """Get a URL for the readonly transport.
 
1200
 
 
1201
        This will either be backed by '.' or a decorator to the transport 
 
1202
        used by self.get_url()
 
1203
        relpath provides for clients to get a path relative to the base url.
 
1204
        These should only be downwards relative, not upwards.
 
1205
        """
 
1206
        base = self.get_readonly_server().get_url()
 
1207
        if relpath is not None:
 
1208
            if not base.endswith('/'):
 
1209
                base = base + '/'
 
1210
            base = base + relpath
 
1211
        return base
 
1212
 
 
1213
    def get_server(self):
 
1214
        """Get the read/write server instance.
 
1215
 
 
1216
        This is useful for some tests with specific servers that need
 
1217
        diagnostics.
 
1218
 
 
1219
        For TestCaseWithMemoryTransport this is always a MemoryServer, and there
 
1220
        is no means to override it.
 
1221
        """
 
1222
        if self.__server is None:
 
1223
            self.__server = MemoryServer()
 
1224
            self.__server.setUp()
 
1225
            self.addCleanup(self.__server.tearDown)
 
1226
        return self.__server
 
1227
 
 
1228
    def get_url(self, relpath=None):
 
1229
        """Get a URL (or maybe a path) for the readwrite transport.
 
1230
 
 
1231
        This will either be backed by '.' or to an equivalent non-file based
 
1232
        facility.
 
1233
        relpath provides for clients to get a path relative to the base url.
 
1234
        These should only be downwards relative, not upwards.
 
1235
        """
 
1236
        base = self.get_server().get_url()
 
1237
        if relpath is not None and relpath != '.':
 
1238
            if not base.endswith('/'):
 
1239
                base = base + '/'
 
1240
            # XXX: Really base should be a url; we did after all call
 
1241
            # get_url()!  But sometimes it's just a path (from
 
1242
            # LocalAbspathServer), and it'd be wrong to append urlescaped data
 
1243
            # to a non-escaped local path.
 
1244
            if base.startswith('./') or base.startswith('/'):
 
1245
                base += relpath
 
1246
            else:
 
1247
                base += urlutils.escape(relpath)
 
1248
        return base
 
1249
 
 
1250
    def _make_test_root(self):
 
1251
        if TestCaseWithMemoryTransport.TEST_ROOT is not None:
 
1252
            return
 
1253
        i = 0
 
1254
        while True:
 
1255
            root = u'test%04d.tmp' % i
 
1256
            try:
 
1257
                os.mkdir(root)
 
1258
            except OSError, e:
 
1259
                if e.errno == errno.EEXIST:
 
1260
                    i += 1
 
1261
                    continue
 
1262
                else:
 
1263
                    raise
 
1264
            # successfully created
 
1265
            TestCaseWithMemoryTransport.TEST_ROOT = osutils.abspath(root)
 
1266
            break
 
1267
        # make a fake bzr directory there to prevent any tests propagating
 
1268
        # up onto the source directory's real branch
 
1269
        bzrdir.BzrDir.create_standalone_workingtree(
 
1270
            TestCaseWithMemoryTransport.TEST_ROOT)
 
1271
 
 
1272
    def makeAndChdirToTestDir(self):
 
1273
        """Create a temporary directories for this one test.
 
1274
        
 
1275
        This must set self.test_home_dir and self.test_dir and chdir to
 
1276
        self.test_dir.
 
1277
        
 
1278
        For TestCaseWithMemoryTransport we chdir to the TEST_ROOT for this test.
 
1279
        """
 
1280
        os.chdir(TestCaseWithMemoryTransport.TEST_ROOT)
 
1281
        self.test_dir = TestCaseWithMemoryTransport.TEST_ROOT
 
1282
        self.test_home_dir = self.test_dir + "/MemoryTransportMissingHomeDir"
 
1283
        
 
1284
    def make_branch(self, relpath, format=None):
 
1285
        """Create a branch on the transport at relpath."""
 
1286
        repo = self.make_repository(relpath, format=format)
 
1287
        return repo.bzrdir.create_branch()
 
1288
 
 
1289
    def make_bzrdir(self, relpath, format=None):
 
1290
        try:
 
1291
            # might be a relative or absolute path
 
1292
            maybe_a_url = self.get_url(relpath)
 
1293
            segments = maybe_a_url.rsplit('/', 1)
 
1294
            t = get_transport(maybe_a_url)
 
1295
            if len(segments) > 1 and segments[-1] not in ('', '.'):
 
1296
                try:
 
1297
                    t.mkdir('.')
 
1298
                except errors.FileExists:
 
1299
                    pass
 
1300
            if format is None:
 
1301
                format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
 
1302
            return format.initialize_on_transport(t)
 
1303
        except errors.UninitializableFormat:
 
1304
            raise TestSkipped("Format %s is not initializable." % format)
 
1305
 
 
1306
    def make_repository(self, relpath, shared=False, format=None):
 
1307
        """Create a repository on our default transport at relpath."""
 
1308
        made_control = self.make_bzrdir(relpath, format=format)
 
1309
        return made_control.create_repository(shared=shared)
 
1310
 
 
1311
    def make_branch_and_memory_tree(self, relpath, format=None):
 
1312
        """Create a branch on the default transport and a MemoryTree for it."""
 
1313
        b = self.make_branch(relpath, format=format)
 
1314
        return memorytree.MemoryTree.create_on_branch(b)
 
1315
 
 
1316
    def overrideEnvironmentForTesting(self):
 
1317
        os.environ['HOME'] = self.test_home_dir
 
1318
        os.environ['APPDATA'] = self.test_home_dir
 
1319
        
 
1320
    def setUp(self):
 
1321
        super(TestCaseWithMemoryTransport, self).setUp()
 
1322
        self._make_test_root()
 
1323
        _currentdir = os.getcwdu()
 
1324
        def _leaveDirectory():
 
1325
            os.chdir(_currentdir)
 
1326
        self.addCleanup(_leaveDirectory)
 
1327
        self.makeAndChdirToTestDir()
 
1328
        self.overrideEnvironmentForTesting()
 
1329
        self.__readonly_server = None
 
1330
        self.__server = None
 
1331
 
989
1332
     
990
 
class TestCaseInTempDir(TestCase):
 
1333
class TestCaseInTempDir(TestCaseWithMemoryTransport):
991
1334
    """Derived class that runs a test within a temporary directory.
992
1335
 
993
1336
    This is useful for tests that need to create a branch, etc.
1000
1343
    InTempDir is an old alias for FunctionalTestCase.
1001
1344
    """
1002
1345
 
1003
 
    TEST_ROOT = None
1004
 
    _TEST_NAME = 'test'
1005
1346
    OVERRIDE_PYTHON = 'python'
1006
1347
 
1007
1348
    def check_file_contents(self, filename, expect):
1012
1353
            self.log("actually: %r" % contents)
1013
1354
            self.fail("contents of %s not as expected" % filename)
1014
1355
 
1015
 
    def _make_test_root(self):
1016
 
        if TestCaseInTempDir.TEST_ROOT is not None:
1017
 
            return
1018
 
        i = 0
1019
 
        while True:
1020
 
            root = u'test%04d.tmp' % i
1021
 
            try:
1022
 
                os.mkdir(root)
1023
 
            except OSError, e:
1024
 
                if e.errno == errno.EEXIST:
1025
 
                    i += 1
1026
 
                    continue
1027
 
                else:
1028
 
                    raise
1029
 
            # successfully created
1030
 
            TestCaseInTempDir.TEST_ROOT = osutils.abspath(root)
1031
 
            break
1032
 
        # make a fake bzr directory there to prevent any tests propagating
1033
 
        # up onto the source directory's real branch
1034
 
        bzrdir.BzrDir.create_standalone_workingtree(TestCaseInTempDir.TEST_ROOT)
1035
 
 
1036
 
    def setUp(self):
1037
 
        super(TestCaseInTempDir, self).setUp()
1038
 
        self._make_test_root()
1039
 
        _currentdir = os.getcwdu()
 
1356
    def makeAndChdirToTestDir(self):
 
1357
        """See TestCaseWithMemoryTransport.makeAndChdirToTestDir().
 
1358
        
 
1359
        For TestCaseInTempDir we create a temporary directory based on the test
 
1360
        name and then create two subdirs - test and home under it.
 
1361
        """
1040
1362
        # shorten the name, to avoid test failures due to path length
1041
1363
        short_id = self.id().replace('bzrlib.tests.', '') \
1042
1364
                   .replace('__main__.', '')[-100:]
1052
1374
                i = i + 1
1053
1375
                continue
1054
1376
            else:
1055
 
                self.test_dir = candidate_dir
 
1377
                os.mkdir(candidate_dir)
 
1378
                self.test_home_dir = candidate_dir + '/home'
 
1379
                os.mkdir(self.test_home_dir)
 
1380
                self.test_dir = candidate_dir + '/work'
1056
1381
                os.mkdir(self.test_dir)
1057
1382
                os.chdir(self.test_dir)
1058
1383
                break
1059
 
        os.environ['HOME'] = self.test_dir
1060
 
        os.environ['APPDATA'] = self.test_dir
1061
 
        def _leaveDirectory():
1062
 
            os.chdir(_currentdir)
1063
 
        self.addCleanup(_leaveDirectory)
1064
 
        
 
1384
 
1065
1385
    def build_tree(self, shape, line_endings='native', transport=None):
1066
1386
        """Build a test tree according to a pattern.
1067
1387
 
1108
1428
    def build_tree_contents(self, shape):
1109
1429
        build_tree_contents(shape)
1110
1430
 
1111
 
    def failUnlessExists(self, path):
1112
 
        """Fail unless path, which may be abs or relative, exists."""
1113
 
        self.failUnless(osutils.lexists(path))
1114
 
 
1115
 
    def failIfExists(self, path):
1116
 
        """Fail if path, which may be abs or relative, exists."""
1117
 
        self.failIf(osutils.lexists(path))
1118
 
        
1119
1431
    def assertFileEqual(self, content, path):
1120
1432
        """Fail if path does not contain 'content'."""
1121
1433
        self.failUnless(osutils.lexists(path))
1137
1449
    readwrite one must both define get_url() as resolving to os.getcwd().
1138
1450
    """
1139
1451
 
1140
 
    def __init__(self, methodName='testMethod'):
1141
 
        super(TestCaseWithTransport, self).__init__(methodName)
1142
 
        self.__readonly_server = None
1143
 
        self.__server = None
1144
 
        self.transport_server = default_transport
1145
 
        self.transport_readonly_server = None
1146
 
 
1147
 
    def get_readonly_url(self, relpath=None):
1148
 
        """Get a URL for the readonly transport.
1149
 
 
1150
 
        This will either be backed by '.' or a decorator to the transport 
1151
 
        used by self.get_url()
1152
 
        relpath provides for clients to get a path relative to the base url.
1153
 
        These should only be downwards relative, not upwards.
1154
 
        """
1155
 
        base = self.get_readonly_server().get_url()
1156
 
        if relpath is not None:
1157
 
            if not base.endswith('/'):
1158
 
                base = base + '/'
1159
 
            base = base + relpath
1160
 
        return base
1161
 
 
1162
 
    def get_readonly_server(self):
1163
 
        """Get the server instance for the readonly transport
1164
 
 
1165
 
        This is useful for some tests with specific servers to do diagnostics.
1166
 
        """
1167
 
        if self.__readonly_server is None:
1168
 
            if self.transport_readonly_server is None:
1169
 
                # readonly decorator requested
1170
 
                # bring up the server
1171
 
                self.get_url()
1172
 
                self.__readonly_server = ReadonlyServer()
1173
 
                self.__readonly_server.setUp(self.__server)
1174
 
            else:
1175
 
                self.__readonly_server = self.transport_readonly_server()
1176
 
                self.__readonly_server.setUp()
1177
 
            self.addCleanup(self.__readonly_server.tearDown)
1178
 
        return self.__readonly_server
1179
 
 
1180
1452
    def get_server(self):
1181
 
        """Get the read/write server instance.
 
1453
        """See TestCaseWithMemoryTransport.
1182
1454
 
1183
1455
        This is useful for some tests with specific servers that need
1184
1456
        diagnostics.
1189
1461
            self.addCleanup(self.__server.tearDown)
1190
1462
        return self.__server
1191
1463
 
1192
 
    def get_url(self, relpath=None):
1193
 
        """Get a URL for the readwrite transport.
1194
 
 
1195
 
        This will either be backed by '.' or to an equivalent non-file based
1196
 
        facility.
1197
 
        relpath provides for clients to get a path relative to the base url.
1198
 
        These should only be downwards relative, not upwards.
1199
 
        """
1200
 
        base = self.get_server().get_url()
1201
 
        if relpath is not None and relpath != '.':
1202
 
            if not base.endswith('/'):
1203
 
                base = base + '/'
1204
 
            base = base + urlutils.escape(relpath)
1205
 
        return base
1206
 
 
1207
 
    def get_transport(self):
1208
 
        """Return a writeable transport for the test scratch space"""
1209
 
        t = get_transport(self.get_url())
1210
 
        self.assertFalse(t.is_readonly())
1211
 
        return t
1212
 
 
1213
 
    def get_readonly_transport(self):
1214
 
        """Return a readonly transport for the test scratch space
1215
 
        
1216
 
        This can be used to test that operations which should only need
1217
 
        readonly access in fact do not try to write.
1218
 
        """
1219
 
        t = get_transport(self.get_readonly_url())
1220
 
        self.assertTrue(t.is_readonly())
1221
 
        return t
1222
 
 
1223
 
    def make_branch(self, relpath, format=None):
1224
 
        """Create a branch on the transport at relpath."""
1225
 
        repo = self.make_repository(relpath, format=format)
1226
 
        return repo.bzrdir.create_branch()
1227
 
 
1228
 
    def make_bzrdir(self, relpath, format=None):
1229
 
        try:
1230
 
            url = self.get_url(relpath)
1231
 
            mutter('relpath %r => url %r', relpath, url)
1232
 
            segments = url.split('/')
1233
 
            if segments and segments[-1] not in ('', '.'):
1234
 
                parent = '/'.join(segments[:-1])
1235
 
                t = get_transport(parent)
1236
 
                try:
1237
 
                    t.mkdir(segments[-1])
1238
 
                except errors.FileExists:
1239
 
                    pass
1240
 
            if format is None:
1241
 
                format=bzrlib.bzrdir.BzrDirFormat.get_default_format()
1242
 
            # FIXME: make this use a single transport someday. RBC 20060418
1243
 
            return format.initialize_on_transport(get_transport(relpath))
1244
 
        except errors.UninitializableFormat:
1245
 
            raise TestSkipped("Format %s is not initializable." % format)
1246
 
 
1247
 
    def make_repository(self, relpath, shared=False, format=None):
1248
 
        """Create a repository on our default transport at relpath."""
1249
 
        made_control = self.make_bzrdir(relpath, format=format)
1250
 
        return made_control.create_repository(shared=shared)
1251
 
 
1252
1464
    def make_branch_and_tree(self, relpath, format=None):
1253
1465
        """Create a branch on the transport and a tree locally.
1254
1466
 
1255
 
        Returns the tree.
 
1467
        If the transport is not a LocalTransport, the Tree can't be created on
 
1468
        the transport.  In that case the working tree is created in the local
 
1469
        directory, and the returned tree's branch and repository will also be
 
1470
        accessed locally.
 
1471
 
 
1472
        This will fail if the original default transport for this test
 
1473
        case wasn't backed by the working directory, as the branch won't
 
1474
        be on disk for us to open it.  
 
1475
 
 
1476
        :param format: The BzrDirFormat.
 
1477
        :returns: the WorkingTree.
1256
1478
        """
1257
1479
        # TODO: always use the local disk path for the working tree,
1258
1480
        # this obviously requires a format that supports branch references
1262
1484
        try:
1263
1485
            return b.bzrdir.create_workingtree()
1264
1486
        except errors.NotLocalUrl:
1265
 
            # new formats - catch No tree error and create
1266
 
            # a branch reference and a checkout.
1267
 
            # old formats at that point - raise TestSkipped.
1268
 
            # TODO: rbc 20060208
1269
 
            return WorkingTreeFormat2().initialize(bzrdir.BzrDir.open(relpath))
 
1487
            # We can only make working trees locally at the moment.  If the
 
1488
            # transport can't support them, then reopen the branch on a local
 
1489
            # transport, and create the working tree there.  
 
1490
            #
 
1491
            # Possibly we should instead keep
 
1492
            # the non-disk-backed branch and create a local checkout?
 
1493
            bd = bzrdir.BzrDir.open(relpath)
 
1494
            return bd.create_workingtree()
1270
1495
 
1271
1496
    def assertIsDirectory(self, relpath, transport):
1272
1497
        """Assert that relpath within transport is a directory.
1283
1508
            self.fail("path %s is not a directory; has mode %#o"
1284
1509
                      % (relpath, mode))
1285
1510
 
 
1511
    def setUp(self):
 
1512
        super(TestCaseWithTransport, self).setUp()
 
1513
        self.__server = None
 
1514
        self.transport_server = default_transport
 
1515
 
1286
1516
 
1287
1517
class ChrootedTestCase(TestCaseWithTransport):
1288
1518
    """A support class that provides readonly urls outside the local namespace.
1314
1544
def run_suite(suite, name='test', verbose=False, pattern=".*",
1315
1545
              stop_on_failure=False, keep_output=False,
1316
1546
              transport=None, lsprof_timed=None, bench_history=None):
1317
 
    TestCaseInTempDir._TEST_NAME = name
1318
1547
    TestCase._gather_lsprof_in_benchmarks = lsprof_timed
1319
1548
    if verbose:
1320
1549
        verbosity = 2
1393
1622
                   'bzrlib.tests.test_errors',
1394
1623
                   'bzrlib.tests.test_escaped_store',
1395
1624
                   'bzrlib.tests.test_fetch',
 
1625
                   'bzrlib.tests.test_ftp_transport',
1396
1626
                   'bzrlib.tests.test_gpg',
1397
1627
                   'bzrlib.tests.test_graph',
1398
1628
                   'bzrlib.tests.test_hashcache',
1402
1632
                   'bzrlib.tests.test_ignores',
1403
1633
                   'bzrlib.tests.test_inv',
1404
1634
                   'bzrlib.tests.test_knit',
 
1635
                   'bzrlib.tests.test_lazy_import',
 
1636
                   'bzrlib.tests.test_lazy_regex',
1405
1637
                   'bzrlib.tests.test_lockdir',
1406
1638
                   'bzrlib.tests.test_lockable_files',
1407
1639
                   'bzrlib.tests.test_log',
 
1640
                   'bzrlib.tests.test_memorytree',
1408
1641
                   'bzrlib.tests.test_merge',
1409
1642
                   'bzrlib.tests.test_merge3',
1410
1643
                   'bzrlib.tests.test_merge_core',
1419
1652
                   'bzrlib.tests.test_plugins',
1420
1653
                   'bzrlib.tests.test_progress',
1421
1654
                   'bzrlib.tests.test_reconcile',
 
1655
                   'bzrlib.tests.test_registry',
1422
1656
                   'bzrlib.tests.test_repository',
1423
1657
                   'bzrlib.tests.test_revert',
1424
1658
                   'bzrlib.tests.test_revision',
1429
1663
                   'bzrlib.tests.test_selftest',
1430
1664
                   'bzrlib.tests.test_setup',
1431
1665
                   'bzrlib.tests.test_sftp_transport',
1432
 
                   'bzrlib.tests.test_ftp_transport',
1433
1666
                   'bzrlib.tests.test_smart_add',
 
1667
                   'bzrlib.tests.test_smart_transport',
1434
1668
                   'bzrlib.tests.test_source',
1435
1669
                   'bzrlib.tests.test_status',
1436
1670
                   'bzrlib.tests.test_store',
1443
1677
                   'bzrlib.tests.test_transform',
1444
1678
                   'bzrlib.tests.test_transport',
1445
1679
                   'bzrlib.tests.test_tree',
 
1680
                   'bzrlib.tests.test_treebuilder',
1446
1681
                   'bzrlib.tests.test_tsort',
1447
1682
                   'bzrlib.tests.test_tuned_gzip',
1448
1683
                   'bzrlib.tests.test_ui',
1450
1685
                   'bzrlib.tests.test_urlutils',
1451
1686
                   'bzrlib.tests.test_versionedfile',
1452
1687
                   'bzrlib.tests.test_version',
 
1688
                   'bzrlib.tests.test_version_info',
1453
1689
                   'bzrlib.tests.test_weave',
1454
1690
                   'bzrlib.tests.test_whitebox',
1455
1691
                   'bzrlib.tests.test_workingtree',
1470
1706
    for m in MODULES_TO_TEST:
1471
1707
        suite.addTest(loader.loadTestsFromModule(m))
1472
1708
    for m in MODULES_TO_DOCTEST:
1473
 
        suite.addTest(doctest.DocTestSuite(m))
 
1709
        try:
 
1710
            suite.addTest(doctest.DocTestSuite(m))
 
1711
        except ValueError, e:
 
1712
            print '**failed to get doctest for: %s\n%s' %(m,e)
 
1713
            raise
1474
1714
    for name, plugin in bzrlib.plugin.all_plugins().items():
1475
1715
        if getattr(plugin, 'test_suite', None) is not None:
1476
1716
            suite.addTest(plugin.test_suite())