27
28
from bzrlib import (
30
32
revision as _mod_revision,
33
34
from bzrlib.branch import Branch
34
35
from bzrlib.bzrdir import BzrDir
35
from bzrlib.errors import ParamikoNotPresent
36
36
from bzrlib.smart import client, medium
37
from bzrlib.smart.server import SmartTCPServer
38
from bzrlib.tests import TestCaseWithTransport, TestSkipped
37
from bzrlib.smart.server import BzrServerFactory, SmartTCPServer
38
from bzrlib.tests import (
40
TestCaseWithMemoryTransport,
41
TestCaseWithTransport,
39
44
from bzrlib.trace import mutter
40
45
from bzrlib.transport import get_transport, remote
43
48
class TestBzrServe(TestCaseWithTransport):
51
super(TestBzrServe, self).setUp()
52
self.disable_missing_extensions_warning()
45
54
def assertInetServerShutsdownCleanly(self, process):
46
55
"""Shutdown the server process looking for errors."""
47
56
# Shutdown the server: the server should shut down when it cannot read
154
166
self.make_read_requests(branch)
155
167
self.assertServerFinishesCleanly(process)
157
def test_bzr_connect_to_bzr_ssh(self):
158
"""User acceptance that get_transport of a bzr+ssh:// behaves correctly.
160
bzr+ssh:// should cause bzr to run a remote bzr smart server over SSH.
163
from bzrlib.transport.sftp import SFTPServer
164
except ParamikoNotPresent:
165
raise TestSkipped('Paramiko not installed')
166
from bzrlib.tests.stub_sftp import StubServer
169
self.make_branch('a_branch')
171
# Start an SSH server
172
self.command_executed = []
173
# XXX: This is horrible -- we define a really dumb SSH server that
174
# executes commands, and manage the hooking up of stdin/out/err to the
175
# SSH channel ourselves. Surely this has already been implemented
177
class StubSSHServer(StubServer):
181
def check_channel_exec_request(self, channel, command):
182
self.test.command_executed.append(command)
183
proc = subprocess.Popen(
184
command, shell=True, stdin=subprocess.PIPE,
185
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
187
# XXX: horribly inefficient, not to mention ugly.
188
# Start a thread for each of stdin/out/err, and relay bytes from
189
# the subprocess to channel and vice versa.
190
def ferry_bytes(read, write, close):
199
(channel.recv, proc.stdin.write, proc.stdin.close),
200
(proc.stdout.read, channel.sendall, channel.close),
201
(proc.stderr.read, channel.sendall_stderr, channel.close)]
202
for read, write, close in file_functions:
203
t = threading.Thread(
204
target=ferry_bytes, args=(read, write, close))
209
ssh_server = SFTPServer(StubSSHServer)
210
# XXX: We *don't* want to override the default SSH vendor, so we set
211
# _vendor to what _get_ssh_vendor returns.
213
self.addCleanup(ssh_server.tearDown)
214
port = ssh_server._listener.port
216
# Access the branch via a bzr+ssh URL. The BZR_REMOTE_PATH environment
217
# variable is used to tell bzr what command to run on the remote end.
218
path_to_branch = osutils.abspath('a_branch')
220
orig_bzr_remote_path = os.environ.get('BZR_REMOTE_PATH')
221
bzr_remote_path = self.get_bzr_path()
222
if sys.platform == 'win32':
223
bzr_remote_path = sys.executable + ' ' + self.get_bzr_path()
224
os.environ['BZR_REMOTE_PATH'] = bzr_remote_path
226
if sys.platform == 'win32':
227
path_to_branch = os.path.splitdrive(path_to_branch)[1]
228
branch = Branch.open(
229
'bzr+ssh://fred:secret@localhost:%d%s' % (port, path_to_branch))
230
self.make_read_requests(branch)
231
# Check we can perform write operations
232
branch.bzrdir.root_transport.mkdir('foo')
234
# Restore the BZR_REMOTE_PATH environment variable back to its
236
if orig_bzr_remote_path is None:
237
del os.environ['BZR_REMOTE_PATH']
239
os.environ['BZR_REMOTE_PATH'] = orig_bzr_remote_path
242
['%s serve --inet --directory=/ --allow-writes'
244
self.command_executed)
247
170
class TestCmdServeChrooting(TestCaseWithTransport):
256
179
t = self.get_transport()
257
180
t.mkdir('server-root')
258
181
self.run_bzr_serve_then_func(
259
['--port', '0', '--directory', t.local_abspath('server-root'),
182
['--port', '127.0.0.1:0',
183
'--directory', t.local_abspath('server-root'),
260
184
'--allow-writes'],
261
185
self.when_server_started)
262
186
# The when_server_started method issued a find_repositoryV3 that should
263
187
# fail with 'norepository' because there are no repositories inside the
265
189
self.assertEqual(('norepository',), self.client_resp)
267
191
def run_bzr_serve_then_func(self, serve_args, func, *func_args,
269
193
"""Run 'bzr serve', and run the given func in a thread once the server
316
240
client_medium.disconnect()
243
class TestUserdirExpansion(TestCaseWithMemoryTransport):
245
def fake_expanduser(self, path):
246
"""A simple, environment-independent, function for the duration of this
249
Paths starting with a path segment of '~user' will expand to start with
250
'/home/user/'. Every other path will be unchanged.
252
if path.split('/', 1)[0] == '~user':
253
return '/home/user' + path[len('~user'):]
256
def make_test_server(self, base_path='/'):
257
"""Make and setUp a BzrServerFactory, backed by a memory transport, and
258
creat '/home/user' in that transport.
260
bzr_server = BzrServerFactory(
261
self.fake_expanduser, lambda t: base_path)
262
mem_transport = self.get_transport()
263
mem_transport.mkdir_multi(['home', 'home/user'])
264
bzr_server.set_up(mem_transport, None, None, inet=True)
265
self.addCleanup(bzr_server.tear_down)
268
def test_bzr_serve_expands_userdir(self):
269
bzr_server = self.make_test_server()
270
self.assertTrue(bzr_server.smart_server.backing_transport.has('~user'))
272
def test_bzr_serve_does_not_expand_userdir_outside_base(self):
273
bzr_server = self.make_test_server('/foo')
274
self.assertFalse(bzr_server.smart_server.backing_transport.has('~user'))
276
def test_get_base_path(self):
277
"""cmd_serve will turn the --directory option into a LocalTransport
278
(optionally decorated with 'readonly+'). BzrServerFactory can
279
determine the original --directory from that transport.
281
# Define a fake 'protocol' to capture the transport that cmd_serve
282
# passes to serve_bzr.
283
def capture_transport(transport, host, port, inet):
284
self.bzr_serve_transport = transport
285
cmd = builtins.cmd_serve()
287
cmd.run(directory='/a/b/c', protocol=capture_transport)
288
server_maker = BzrServerFactory()
290
'readonly+file:///a/b/c/', self.bzr_serve_transport.base)
292
u'/a/b/c/', server_maker.get_base_path(self.bzr_serve_transport))
294
cmd.run(directory='/a/b/c', protocol=capture_transport,
296
server_maker = BzrServerFactory()
297
self.assertEqual('file:///a/b/c/', self.bzr_serve_transport.base)
299
u'/a/b/c/', server_maker.get_base_path(self.bzr_serve_transport))