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)
886
class TestSSHConnections(tests.TestCaseWithTransport):
888
def test_bzr_connect_to_bzr_ssh(self):
889
"""User acceptance that get_transport of a bzr+ssh:// behaves correctly.
891
bzr+ssh:// should cause bzr to run a remote bzr smart server over SSH.
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
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
911
class StubSSHServer(StubServer):
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)
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):
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))
943
ssh_server = SFTPFullAbsoluteServer(StubSSHServer)
944
# We *don't* want to override the default SSH vendor: the detected one
946
self.start_server(ssh_server)
947
port = ssh_server._listener.port
949
if sys.platform == 'win32':
950
bzr_remote_path = sys.executable + ' ' + self.get_bzr_path()
952
bzr_remote_path = self.get_bzr_path()
953
os.environ['BZR_REMOTE_PATH'] = bzr_remote_path
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)
968
['%s serve --inet --directory=/ --allow-writes' % bzr_remote_path],
969
self.command_executed)