28
28
from bzrlib import (
33
32
revision as _mod_revision,
36
34
from bzrlib.branch import Branch
37
35
from bzrlib.bzrdir import BzrDir
36
from bzrlib.errors import ParamikoNotPresent
38
37
from bzrlib.smart import client, medium
39
38
from bzrlib.smart.server import BzrServerFactory, SmartTCPServer
40
39
from bzrlib.tests import (
40
TestCaseWithTransport,
41
41
TestCaseWithMemoryTransport,
42
TestCaseWithTransport,
45
44
from bzrlib.trace import mutter
46
45
from bzrlib.transport import get_transport, remote
49
class TestBzrServeBase(TestCaseWithTransport):
51
def run_bzr_serve_then_func(self, serve_args, retcode=0, func=None,
52
*func_args, **func_kwargs):
53
"""Run 'bzr serve', and run the given func in a thread once the server
56
When 'func' terminates, the server will be terminated too.
58
Returns stdout and stderr.
61
def on_server_start(backing_urls, tcp_server):
63
target=on_server_start_thread, args=(tcp_server,))
65
def on_server_start_thread(tcp_server):
68
self.tcp_server = tcp_server
71
func(*func_args, **func_kwargs)
73
# Log errors to make some test failures a little less
75
mutter('func broke: %r', e)
77
# Then stop the server
78
mutter('interrupting...')
79
thread.interrupt_main()
80
SmartTCPServer.hooks.install_named_hook(
81
'server_started_ex', on_server_start,
82
'run_bzr_serve_then_func hook')
85
out, err = self.run_bzr(['serve'] + list(serve_args))
86
except KeyboardInterrupt, e:
91
class TestBzrServe(TestBzrServeBase):
48
class TestBzrServe(TestCaseWithTransport):
94
51
super(TestBzrServe, self).setUp()
219
166
self.make_read_requests(branch)
220
167
self.assertServerFinishesCleanly(process)
222
def test_bzr_serve_dhpss(self):
223
# This is a smoke test that the server doesn't crash when run with
224
# -Dhpss, and does drop some hpss logging to the file.
225
self.make_branch('.')
226
log_fname = os.getcwd() + '/server.log'
227
self._captureVar('BZR_LOG', log_fname)
228
process, transport = self.start_server_inet(['-Dhpss'])
229
branch = BzrDir.open_from_transport(transport).open_branch()
230
self.make_read_requests(branch)
231
self.assertInetServerShutsdownCleanly(process)
232
f = open(log_fname, 'rb')
235
self.assertContainsRe(content, r'hpss request: \[[0-9-]+\]')
238
class TestCmdServeChrooting(TestBzrServeBase):
169
def test_bzr_connect_to_bzr_ssh(self):
170
"""User acceptance that get_transport of a bzr+ssh:// behaves correctly.
172
bzr+ssh:// should cause bzr to run a remote bzr smart server over SSH.
175
# SFTPFullAbsoluteServer has a get_url method, and doesn't
176
# override the interface (doesn't change self._vendor).
177
from bzrlib.transport.sftp import SFTPFullAbsoluteServer
178
except ParamikoNotPresent:
179
raise TestSkipped('Paramiko not installed')
180
from bzrlib.tests.stub_sftp import StubServer
183
self.make_branch('a_branch')
185
# Start an SSH server
186
self.command_executed = []
187
# XXX: This is horrible -- we define a really dumb SSH server that
188
# executes commands, and manage the hooking up of stdin/out/err to the
189
# SSH channel ourselves. Surely this has already been implemented
191
class StubSSHServer(StubServer):
195
def check_channel_exec_request(self, channel, command):
196
self.test.command_executed.append(command)
197
proc = subprocess.Popen(
198
command, shell=True, stdin=subprocess.PIPE,
199
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
201
# XXX: horribly inefficient, not to mention ugly.
202
# Start a thread for each of stdin/out/err, and relay bytes from
203
# the subprocess to channel and vice versa.
204
def ferry_bytes(read, write, close):
213
(channel.recv, proc.stdin.write, proc.stdin.close),
214
(proc.stdout.read, channel.sendall, channel.close),
215
(proc.stderr.read, channel.sendall_stderr, channel.close)]
216
for read, write, close in file_functions:
217
t = threading.Thread(
218
target=ferry_bytes, args=(read, write, close))
223
ssh_server = SFTPFullAbsoluteServer(StubSSHServer)
224
# XXX: We *don't* want to override the default SSH vendor, so we set
225
# _vendor to what _get_ssh_vendor returns.
226
self.start_server(ssh_server)
227
port = ssh_server._listener.port
229
# Access the branch via a bzr+ssh URL. The BZR_REMOTE_PATH environment
230
# variable is used to tell bzr what command to run on the remote end.
231
path_to_branch = osutils.abspath('a_branch')
233
orig_bzr_remote_path = os.environ.get('BZR_REMOTE_PATH')
234
bzr_remote_path = self.get_bzr_path()
235
if sys.platform == 'win32':
236
bzr_remote_path = sys.executable + ' ' + self.get_bzr_path()
237
os.environ['BZR_REMOTE_PATH'] = bzr_remote_path
239
if sys.platform == 'win32':
240
path_to_branch = os.path.splitdrive(path_to_branch)[1]
241
url_suffix = '@localhost:%d%s' % (port, path_to_branch)
242
self.permit_url('bzr+ssh://fred' + url_suffix)
243
branch = Branch.open('bzr+ssh://fred:secret' + url_suffix)
244
self.make_read_requests(branch)
245
# Check we can perform write operations
246
branch.bzrdir.root_transport.mkdir('foo')
248
# Restore the BZR_REMOTE_PATH environment variable back to its
250
if orig_bzr_remote_path is None:
251
del os.environ['BZR_REMOTE_PATH']
253
os.environ['BZR_REMOTE_PATH'] = orig_bzr_remote_path
256
['%s serve --inet --directory=/ --allow-writes'
258
self.command_executed)
261
class TestCmdServeChrooting(TestCaseWithTransport):
240
263
def test_serve_tcp(self):
241
264
"""'bzr serve' wraps the given --directory in a ChrootServer.
250
273
['--port', '127.0.0.1:0',
251
274
'--directory', t.local_abspath('server-root'),
252
275
'--allow-writes'],
253
func=self.when_server_started)
276
self.when_server_started)
254
277
# The when_server_started method issued a find_repositoryV3 that should
255
278
# fail with 'norepository' because there are no repositories inside the
257
280
self.assertEqual(('norepository',), self.client_resp)
282
def run_bzr_serve_then_func(self, serve_args, func, *func_args,
284
"""Run 'bzr serve', and run the given func in a thread once the server
287
When 'func' terminates, the server will be terminated too.
290
def on_server_start(backing_urls, tcp_server):
291
t = threading.Thread(
292
target=on_server_start_thread, args=(tcp_server,))
294
def on_server_start_thread(tcp_server):
297
self.tcp_server = tcp_server
299
func(*func_args, **func_kwargs)
301
# Log errors to make some test failures a little less
303
mutter('func broke: %r', e)
305
# Then stop the server
306
mutter('interrupting...')
307
thread.interrupt_main()
308
SmartTCPServer.hooks.install_named_hook(
309
'server_started_ex', on_server_start,
310
'run_bzr_serve_then_func hook')
313
self.run_bzr(['serve'] + list(serve_args))
314
except KeyboardInterrupt:
259
317
def when_server_started(self):
260
318
# Connect to the TCP server and issue some requests and see what comes
311
369
(optionally decorated with 'readonly+'). BzrServerFactory can
312
370
determine the original --directory from that transport.
314
# URLs always include the trailing slash, and get_base_path returns it
315
base_dir = osutils.abspath('/a/b/c') + '/'
316
base_url = urlutils.local_path_to_url(base_dir) + '/'
317
372
# Define a fake 'protocol' to capture the transport that cmd_serve
318
373
# passes to serve_bzr.
319
374
def capture_transport(transport, host, port, inet):
320
375
self.bzr_serve_transport = transport
321
376
cmd = builtins.cmd_serve()
323
cmd.run(directory=base_dir, protocol=capture_transport)
378
cmd.run(directory='/a/b/c', protocol=capture_transport)
324
379
server_maker = BzrServerFactory()
325
380
self.assertEqual(
326
'readonly+%s' % base_url, self.bzr_serve_transport.base)
381
'readonly+file:///a/b/c/', self.bzr_serve_transport.base)
327
382
self.assertEqual(
328
base_dir, server_maker.get_base_path(self.bzr_serve_transport))
383
u'/a/b/c/', server_maker.get_base_path(self.bzr_serve_transport))
330
cmd.run(directory=base_dir, protocol=capture_transport,
385
cmd.run(directory='/a/b/c', protocol=capture_transport,
331
386
allow_writes=True)
332
387
server_maker = BzrServerFactory()
333
self.assertEqual(base_url, self.bzr_serve_transport.base)
334
self.assertEqual(base_dir,
335
server_maker.get_base_path(self.bzr_serve_transport))
388
self.assertEqual('file:///a/b/c/', self.bzr_serve_transport.base)
390
u'/a/b/c/', server_maker.get_base_path(self.bzr_serve_transport))