/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/blackbox/test_serve.py

  • Committer: Aaron Bentley
  • Date: 2009-09-29 04:40:55 UTC
  • mfrom: (4717 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4718.
  • Revision ID: aaron@aaronbentley.com-20090929044055-e9jtpmz6eyut711h
Merged bzr.dev into fix_get_mtime.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
"""Tests of the bzr serve command."""
19
19
 
20
20
import os
 
21
import os.path
21
22
import signal
22
23
import subprocess
23
24
import sys
25
26
import threading
26
27
 
27
28
from bzrlib import (
 
29
    builtins,
28
30
    errors,
29
31
    osutils,
30
32
    revision as _mod_revision,
31
 
    transport,
32
33
    )
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 (
 
39
    ParamikoFeature,
 
40
    TestCaseWithMemoryTransport,
 
41
    TestCaseWithTransport,
 
42
    TestSkipped,
 
43
    )
39
44
from bzrlib.trace import mutter
40
45
from bzrlib.transport import get_transport, remote
41
46
 
42
47
 
43
48
class TestBzrServe(TestCaseWithTransport):
44
49
 
 
50
    def setUp(self):
 
51
        super(TestBzrServe, self).setUp()
 
52
        self.disable_missing_extensions_warning()
 
53
 
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
85
94
        # We use this url because while this is no valid URL to connect to this
86
95
        # server instance, the transport needs a URL.
87
96
        url = 'bzr://localhost/'
 
97
        self.permit_url(url)
88
98
        client_medium = medium.SmartSimplePipesClientMedium(
89
99
            process.stdout, process.stdin, url)
90
100
        transport = remote.RemoteTransport(url, medium=client_medium)
105
115
        prefix = 'listening on port: '
106
116
        self.assertStartsWith(port_line, prefix)
107
117
        port = int(port_line[len(prefix):])
108
 
        return process,'bzr://localhost:%d/' % port
 
118
        url = 'bzr://localhost:%d/' % port
 
119
        self.permit_url(url)
 
120
        return process, url
109
121
 
110
122
    def test_bzr_serve_inet_readonly(self):
111
123
        """bzr server should provide a read only filesystem by default."""
154
166
        self.make_read_requests(branch)
155
167
        self.assertServerFinishesCleanly(process)
156
168
 
157
 
    def test_bzr_connect_to_bzr_ssh(self):
158
 
        """User acceptance that get_transport of a bzr+ssh:// behaves correctly.
159
 
 
160
 
        bzr+ssh:// should cause bzr to run a remote bzr smart server over SSH.
161
 
        """
162
 
        try:
163
 
            from bzrlib.transport.sftp import SFTPServer
164
 
        except ParamikoNotPresent:
165
 
            raise TestSkipped('Paramiko not installed')
166
 
        from bzrlib.tests.stub_sftp import StubServer
167
 
 
168
 
        # Make a branch
169
 
        self.make_branch('a_branch')
170
 
 
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
176
 
        # elsewhere?
177
 
        class StubSSHServer(StubServer):
178
 
 
179
 
            test = self
180
 
 
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)
186
 
 
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):
191
 
                    while True:
192
 
                        bytes = read(1)
193
 
                        if bytes == '':
194
 
                            close()
195
 
                            break
196
 
                        write(bytes)
197
 
 
198
 
                file_functions = [
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))
205
 
                    t.start()
206
 
 
207
 
                return True
208
 
 
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.
212
 
        ssh_server.setUp()
213
 
        self.addCleanup(ssh_server.tearDown)
214
 
        port = ssh_server._listener.port
215
 
 
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')
219
 
 
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
225
 
        try:
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')
233
 
        finally:
234
 
            # Restore the BZR_REMOTE_PATH environment variable back to its
235
 
            # original state.
236
 
            if orig_bzr_remote_path is None:
237
 
                del os.environ['BZR_REMOTE_PATH']
238
 
            else:
239
 
                os.environ['BZR_REMOTE_PATH'] = orig_bzr_remote_path
240
 
 
241
 
        self.assertEqual(
242
 
            ['%s serve --inet --directory=/ --allow-writes'
243
 
             % bzr_remote_path],
244
 
            self.command_executed)
245
 
 
246
169
 
247
170
class TestCmdServeChrooting(TestCaseWithTransport):
248
171
 
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
264
188
        # --directory.
265
189
        self.assertEqual(('norepository',), self.client_resp)
266
 
        
 
190
 
267
191
    def run_bzr_serve_then_func(self, serve_args, func, *func_args,
268
192
            **func_kwargs):
269
193
        """Run 'bzr serve', and run the given func in a thread once the server
316
240
        client_medium.disconnect()
317
241
 
318
242
 
 
243
class TestUserdirExpansion(TestCaseWithMemoryTransport):
 
244
 
 
245
    def fake_expanduser(self, path):
 
246
        """A simple, environment-independent, function for the duration of this
 
247
        test.
 
248
 
 
249
        Paths starting with a path segment of '~user' will expand to start with
 
250
        '/home/user/'.  Every other path will be unchanged.
 
251
        """
 
252
        if path.split('/', 1)[0] == '~user':
 
253
            return '/home/user' + path[len('~user'):]
 
254
        return path
 
255
 
 
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.
 
259
        """
 
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)
 
266
        return bzr_server
 
267
 
 
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'))
 
271
 
 
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'))
 
275
 
 
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.
 
280
        """
 
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()
 
286
        # Read-only
 
287
        cmd.run(directory='/a/b/c', protocol=capture_transport)
 
288
        server_maker = BzrServerFactory()
 
289
        self.assertEqual(
 
290
            'readonly+file:///a/b/c/', self.bzr_serve_transport.base)
 
291
        self.assertEqual(
 
292
            u'/a/b/c/', server_maker.get_base_path(self.bzr_serve_transport))
 
293
        # Read-write
 
294
        cmd.run(directory='/a/b/c', protocol=capture_transport,
 
295
            allow_writes=True)
 
296
        server_maker = BzrServerFactory()
 
297
        self.assertEqual('file:///a/b/c/', self.bzr_serve_transport.base)
 
298
        self.assertEqual(
 
299
            u'/a/b/c/', server_maker.get_base_path(self.bzr_serve_transport))
319
300