~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_transport.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-09-22 05:29:23 UTC
  • mfrom: (4700.1.3 integration)
  • Revision ID: pqm@pqm.ubuntu.com-20090922052923-oj9unuqio1uf2f1b
(robertc) Cleanup end to end SSH connection test,
        hopefully fixing it on windows too. (Robert Collins,
        John Arbash Meinel)

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
 
18
18
from cStringIO import StringIO
 
19
import os
 
20
import subprocess
 
21
import sys
 
22
import threading
19
23
 
20
24
import bzrlib
21
25
from bzrlib import (
22
26
    errors,
23
27
    osutils,
 
28
    tests,
24
29
    urlutils,
25
30
    )
26
31
from bzrlib.errors import (DependencyNotPresent,
31
36
                           ReadError,
32
37
                           UnsupportedProtocol,
33
38
                           )
34
 
from bzrlib.tests import TestCase, TestCaseInTempDir
 
39
from bzrlib.tests import ParamikoFeature, TestCase, TestCaseInTempDir
35
40
from bzrlib.transport import (_clear_protocol_handlers,
36
41
                              _CoalescedOffset,
37
42
                              ConnectedTransport,
876
881
        # readv records the supplied offset request
877
882
        expected_result.append(('readv', 'foo', [(0, 1), (3, 2)], True, 6))
878
883
        self.assertEqual(expected_result, transport._activity)
 
884
 
 
885
 
 
886
class TestSSHConnections(tests.TestCaseWithTransport):
 
887
 
 
888
    def test_bzr_connect_to_bzr_ssh(self):
 
889
        """User acceptance that get_transport of a bzr+ssh:// behaves correctly.
 
890
 
 
891
        bzr+ssh:// should cause bzr to run a remote bzr smart server over SSH.
 
892
        """
 
893
        # This test actually causes a bzr instance to be invoked, which is very
 
894
        # expensive: it should be the only such test in the test suite.
 
895
        # A reasonable evolution for this would be to simply check inside
 
896
        # check_channel_exec_request that the command is appropriate, and then
 
897
        # satisfy requests in-process.
 
898
        self.requireFeature(ParamikoFeature)
 
899
        # SFTPFullAbsoluteServer has a get_url method, and doesn't
 
900
        # override the interface (doesn't change self._vendor).
 
901
        # Note that this does encryption, so can be slow.
 
902
        from bzrlib.transport.sftp import SFTPFullAbsoluteServer
 
903
        from bzrlib.tests.stub_sftp import StubServer
 
904
 
 
905
        # Start an SSH server
 
906
        self.command_executed = []
 
907
        # XXX: This is horrible -- we define a really dumb SSH server that
 
908
        # executes commands, and manage the hooking up of stdin/out/err to the
 
909
        # SSH channel ourselves.  Surely this has already been implemented
 
910
        # elsewhere?
 
911
        class StubSSHServer(StubServer):
 
912
 
 
913
            test = self
 
914
 
 
915
            def check_channel_exec_request(self, channel, command):
 
916
                self.test.command_executed.append(command)
 
917
                proc = subprocess.Popen(
 
918
                    command, shell=True, stdin=subprocess.PIPE,
 
919
                    stdout=subprocess.PIPE, stderr=subprocess.PIPE)
 
920
 
 
921
                # XXX: horribly inefficient, not to mention ugly.
 
922
                # Start a thread for each of stdin/out/err, and relay bytes from
 
923
                # the subprocess to channel and vice versa.
 
924
                def ferry_bytes(read, write, close):
 
925
                    while True:
 
926
                        bytes = read(1)
 
927
                        if bytes == '':
 
928
                            close()
 
929
                            break
 
930
                        write(bytes)
 
931
 
 
932
                file_functions = [
 
933
                    (channel.recv, proc.stdin.write, proc.stdin.close),
 
934
                    (proc.stdout.read, channel.sendall, channel.close),
 
935
                    (proc.stderr.read, channel.sendall_stderr, channel.close)]
 
936
                for read, write, close in file_functions:
 
937
                    t = threading.Thread(
 
938
                        target=ferry_bytes, args=(read, write, close))
 
939
                    t.start()
 
940
 
 
941
                return True
 
942
 
 
943
        ssh_server = SFTPFullAbsoluteServer(StubSSHServer)
 
944
        # We *don't* want to override the default SSH vendor: the detected one
 
945
        # is the one to use.
 
946
        self.start_server(ssh_server)
 
947
        port = ssh_server._listener.port
 
948
 
 
949
        if sys.platform == 'win32':
 
950
            bzr_remote_path = sys.executable + ' ' + self.get_bzr_path()
 
951
        else:
 
952
            bzr_remote_path = self.get_bzr_path()
 
953
        os.environ['BZR_REMOTE_PATH'] = bzr_remote_path
 
954
 
 
955
        # Access the branch via a bzr+ssh URL.  The BZR_REMOTE_PATH environment
 
956
        # variable is used to tell bzr what command to run on the remote end.
 
957
        path_to_branch = osutils.abspath('.')
 
958
        if sys.platform == 'win32':
 
959
            # On Windows, we export all drives as '/C:/, etc. So we need to
 
960
            # prefix a '/' to get the right path.
 
961
            path_to_branch = '/' + path_to_branch
 
962
        url = 'bzr+ssh://fred:secret@localhost:%d%s' % (port, path_to_branch)
 
963
        t = get_transport(url)
 
964
        self.permit_url(t.base)
 
965
        t.mkdir('foo')
 
966
 
 
967
        self.assertEqual(
 
968
            ['%s serve --inet --directory=/ --allow-writes' % bzr_remote_path],
 
969
            self.command_executed)