~bzr-pqm/bzr/bzr.dev

5557.1.7 by John Arbash Meinel
Merge in the bzr.dev 5582
1
# Copyright (C) 2006-2011 Canonical Ltd
1910.19.7 by Andrew Bennetts
Allow specifying the host/interface to bzr serve, and use the new test
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1910.19.7 by Andrew Bennetts
Allow specifying the host/interface to bzr serve, and use the new test
16
17
18
"""Tests of the bzr serve command."""
19
2018.1.2 by Andrew Bennetts
Tidy imports, skip test if paramiko isn't installed.
20
import os
1910.19.7 by Andrew Bennetts
Allow specifying the host/interface to bzr serve, and use the new test
21
import signal
5929.2.6 by Vincent Ladeuil
Clarify the design a bit and make the test more precise and more robust.
22
import sys
4544.1.2 by Andrew Bennetts
Add test that would catch the lack of ChrootServer in cmd_serve.
23
import thread
2018.1.2 by Andrew Bennetts
Tidy imports, skip test if paramiko isn't installed.
24
import threading
1910.19.7 by Andrew Bennetts
Allow specifying the host/interface to bzr serve, and use the new test
25
2309.2.5 by Alexander Belchenko
test_bzr_connect_to_bzr_ssh: win32-compatibility
26
from bzrlib import (
4634.43.8 by Andrew Bennetts
Test for recovering the --directory value from the transport cmd_serve passes to bzr_serve.
27
    builtins,
6133.4.21 by John Arbash Meinel
I'm trying to make sure that 'bzr serve' supports the serve.client_timeout code.
28
    config,
2309.2.5 by Alexander Belchenko
test_bzr_connect_to_bzr_ssh: win32-compatibility
29
    errors,
30
    osutils,
2598.5.1 by Aaron Bentley
Start eliminating the use of None to indicate null revision
31
    revision as _mod_revision,
5929.2.6 by Vincent Ladeuil
Clarify the design a bit and make the test more precise and more robust.
32
    trace,
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
33
    transport,
4797.3.21 by John Arbash Meinel
Use urlutils.local_path_to_url to handle both windows and linux.
34
    urlutils,
2309.2.5 by Alexander Belchenko
test_bzr_connect_to_bzr_ssh: win32-compatibility
35
    )
1910.19.7 by Andrew Bennetts
Allow specifying the host/interface to bzr serve, and use the new test
36
from bzrlib.branch import Branch
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
37
from bzrlib.bzrdir import BzrDir
4544.1.2 by Andrew Bennetts
Add test that would catch the lack of ChrootServer in cmd_serve.
38
from bzrlib.smart import client, medium
5611.1.2 by Jelmer Vernooij
Add some tests for the hooks.
39
from bzrlib.smart.server import (
40
    BzrServerFactory,
41
    SmartTCPServer,
42
    )
4634.43.7 by Andrew Bennetts
Add some unit tests for parts of userdir expansion.
43
from bzrlib.tests import (
4700.1.3 by Robert Collins
Merge trunk.
44
    TestCaseWithMemoryTransport,
4634.43.7 by Andrew Bennetts
Add some unit tests for parts of userdir expansion.
45
    TestCaseWithTransport,
46
    )
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
47
from bzrlib.transport import remote
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
48
4911.1.1 by John Arbash Meinel
Threads don't have 'get_ident()' attributes. I think spiv meant 'getName()'.
49
4815.3.7 by Gordon Tyler
Made a few changes at the suggestion of vila.
50
class TestBzrServeBase(TestCaseWithTransport):
4815.3.3 by Gordon Tyler
Changed test_bzr_serve_quiet to use in-process execution of the command.
51
52
    def run_bzr_serve_then_func(self, serve_args, retcode=0, func=None,
53
                                *func_args, **func_kwargs):
54
        """Run 'bzr serve', and run the given func in a thread once the server
55
        has started.
5611.1.2 by Jelmer Vernooij
Add some tests for the hooks.
56
4815.3.3 by Gordon Tyler
Changed test_bzr_serve_quiet to use in-process execution of the command.
57
        When 'func' terminates, the server will be terminated too.
5611.1.2 by Jelmer Vernooij
Add some tests for the hooks.
58
4815.3.3 by Gordon Tyler
Changed test_bzr_serve_quiet to use in-process execution of the command.
59
        Returns stdout and stderr.
60
        """
61
        def on_server_start_thread(tcp_server):
5929.2.6 by Vincent Ladeuil
Clarify the design a bit and make the test more precise and more robust.
62
            """This runs concurrently with the server thread.
63
64
            The server is interrupted as soon as ``func`` finishes, even if an
65
            exception is encountered.
66
            """
4815.3.3 by Gordon Tyler
Changed test_bzr_serve_quiet to use in-process execution of the command.
67
            try:
68
                # Run func if set
69
                self.tcp_server = tcp_server
6133.4.34 by John Arbash Meinel
get the blackbox tests passing.
70
                if func is not None:
4815.3.3 by Gordon Tyler
Changed test_bzr_serve_quiet to use in-process execution of the command.
71
                    try:
72
                        func(*func_args, **func_kwargs)
73
                    except Exception, e:
74
                        # Log errors to make some test failures a little less
75
                        # mysterious.
5929.2.6 by Vincent Ladeuil
Clarify the design a bit and make the test more precise and more robust.
76
                        trace.mutter('func broke: %r', e)
4815.3.3 by Gordon Tyler
Changed test_bzr_serve_quiet to use in-process execution of the command.
77
            finally:
78
                # Then stop the server
5929.2.6 by Vincent Ladeuil
Clarify the design a bit and make the test more precise and more robust.
79
                trace.mutter('interrupting...')
4815.3.3 by Gordon Tyler
Changed test_bzr_serve_quiet to use in-process execution of the command.
80
                thread.interrupt_main()
5929.2.6 by Vincent Ladeuil
Clarify the design a bit and make the test more precise and more robust.
81
        # When the hook is fired, it just starts ``on_server_start_thread`` and
82
        # return
83
        def on_server_start(backing_urls, tcp_server):
84
            t = threading.Thread(
85
                target=on_server_start_thread, args=(tcp_server,))
86
            t.start()
87
        # install hook
4815.3.3 by Gordon Tyler
Changed test_bzr_serve_quiet to use in-process execution of the command.
88
        SmartTCPServer.hooks.install_named_hook(
89
            'server_started_ex', on_server_start,
90
            'run_bzr_serve_then_func hook')
6133.4.34 by John Arbash Meinel
get the blackbox tests passing.
91
        # It seesm thread.interrupt_main() will not raise KeyboardInterrupt
92
        # until after socket.accept returns. So we set the timeout low to make
93
        # the test faster.
94
        self.overrideAttr(SmartTCPServer, '_ACCEPT_TIMEOUT', 0.1)
4815.3.3 by Gordon Tyler
Changed test_bzr_serve_quiet to use in-process execution of the command.
95
        # start a TCP server
96
        try:
5929.2.6 by Vincent Ladeuil
Clarify the design a bit and make the test more precise and more robust.
97
            out, err = self.run_bzr(['serve'] + list(serve_args),
98
                                    retcode=retcode)
4815.3.7 by Gordon Tyler
Made a few changes at the suggestion of vila.
99
        except KeyboardInterrupt, e:
100
            out, err = e.args
101
        return out, err
102
103
104
class TestBzrServe(TestBzrServeBase):
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
105
4695.3.1 by Vincent Ladeuil
Fix test failures with no C extensions loaded.
106
    def setUp(self):
4815.3.6 by Gordon Tyler
Fixed super call in TestBzrServe.
107
        super(TestBzrServe, self).setUp()
4695.3.2 by Vincent Ladeuil
Simplified and claried as per Robert's review.
108
        self.disable_missing_extensions_warning()
4695.3.1 by Vincent Ladeuil
Fix test failures with no C extensions loaded.
109
5909.2.5 by Jonathan Riddell
split test into two tests
110
    def test_server_exception_with_hook(self):
5929.2.6 by Vincent Ladeuil
Clarify the design a bit and make the test more precise and more robust.
111
        """Catch exception from the server in the server_exception hook.
112
113
        We use ``run_bzr_serve_then_func`` without a ``func`` so the server
114
        will receive a KeyboardInterrupt exception we want to catch.
115
        """
5909.2.3 by Jonathan Riddell
add test for server exception hook. Also ensure return code is checked in run_bzr_serve_then_func()
116
        def hook(exception):
5929.2.6 by Vincent Ladeuil
Clarify the design a bit and make the test more precise and more robust.
117
            if exception[0] is KeyboardInterrupt:
118
                sys.stderr.write('catching KeyboardInterrupt\n')
119
                return True
120
            else:
121
                return False
5909.2.3 by Jonathan Riddell
add test for server exception hook. Also ensure return code is checked in run_bzr_serve_then_func()
122
        SmartTCPServer.hooks.install_named_hook(
123
            'server_exception', hook,
124
            'test_server_except_hook hook')
5929.2.3 by Vincent Ladeuil
Since the exception is thrown/caught in a thread and the 'listening on port' is emitted by another thread and since synchrozining them is way out of scope for the test, it's easier to just not emit the 'listening' line. So we just tell the server to "Don't do that!".
125
        args = ['--port', 'localhost:0', '--quiet']
5909.2.3 by Jonathan Riddell
add test for server exception hook. Also ensure return code is checked in run_bzr_serve_then_func()
126
        out, err = self.run_bzr_serve_then_func(args, retcode=0)
5929.2.6 by Vincent Ladeuil
Clarify the design a bit and make the test more precise and more robust.
127
        self.assertEqual('catching KeyboardInterrupt\n', err)
5909.2.3 by Jonathan Riddell
add test for server exception hook. Also ensure return code is checked in run_bzr_serve_then_func()
128
5909.2.5 by Jonathan Riddell
split test into two tests
129
    def test_server_exception_no_hook(self):
130
        """test exception without hook returns error"""
131
        args = []
132
        out, err = self.run_bzr_serve_then_func(args, retcode=3)
133
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
134
    def assertInetServerShutsdownCleanly(self, process):
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
135
        """Shutdown the server process looking for errors."""
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
136
        # Shutdown the server: the server should shut down when it cannot read
137
        # from stdin anymore.
138
        process.stdin.close()
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
139
        # Hide stdin from the subprocess module, so it won't fail to close it.
140
        process.stdin = None
2581.1.2 by Martin Pool
Remove unnecessary retcode=0 to run_bzr calls
141
        result = self.finish_bzr_subprocess(process)
1910.19.11 by Andrew Bennetts
General code cleanup based on review comments and other observations.
142
        self.assertEqual('', result[0])
143
        self.assertEqual('', result[1])
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
144
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
145
    def assertServerFinishesCleanly(self, process):
146
        """Shutdown the bzr serve instance process looking for errors."""
147
        # Shutdown the server
148
        result = self.finish_bzr_subprocess(process, retcode=3,
149
                                            send_signal=signal.SIGINT)
150
        self.assertEqual('', result[0])
151
        self.assertEqual('bzr: interrupted\n', result[1])
152
3287.6.4 by Robert Collins
Fix up deprecation warnings for get_revision_graph.
153
    def make_read_requests(self, branch):
154
        """Do some read only requests."""
155
        branch.lock_read()
156
        try:
157
            branch.repository.all_revision_ids()
158
            self.assertEqual(_mod_revision.NULL_REVISION,
159
                             _mod_revision.ensure_null(branch.last_revision()))
160
        finally:
161
            branch.unlock()
162
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
163
    def start_server_inet(self, extra_options=()):
164
        """Start a bzr server subprocess using the --inet option.
165
166
        :param extra_options: extra options to give the server.
167
        :return: a tuple with the bzr process handle for passing to
168
            finish_bzr_subprocess, a client for the server, and a transport.
169
        """
170
        # Serve from the current directory
4911.1.1 by John Arbash Meinel
Threads don't have 'get_ident()' attributes. I think spiv meant 'getName()'.
171
        args = ['serve', '--inet']
172
        args.extend(extra_options)
173
        process = self.start_bzr_subprocess(args)
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
174
175
        # Connect to the server
176
        # We use this url because while this is no valid URL to connect to this
177
        # server instance, the transport needs a URL.
3431.3.7 by Andrew Bennetts
Fix incidental breakage in blackbox/test_serve.py
178
        url = 'bzr://localhost/'
4691.2.1 by Robert Collins
Add stronger test isolation by interception BzrDir.open and checking the thing being opened is known to the test suite.
179
        self.permit_url(url)
2018.5.15 by Andrew Bennetts
Tidy some imports, and bugs introduced when adding server.py
180
        client_medium = medium.SmartSimplePipesClientMedium(
3431.3.7 by Andrew Bennetts
Fix incidental breakage in blackbox/test_serve.py
181
            process.stdout, process.stdin, url)
182
        transport = remote.RemoteTransport(url, medium=client_medium)
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
183
        return process, transport
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
184
185
    def start_server_port(self, extra_options=()):
186
        """Start a bzr server subprocess.
187
188
        :param extra_options: extra options to give the server.
189
        :return: a tuple with the bzr process handle for passing to
190
            finish_bzr_subprocess, and the base url for the server.
191
        """
192
        # Serve from the current directory
193
        args = ['serve', '--port', 'localhost:0']
194
        args.extend(extra_options)
195
        process = self.start_bzr_subprocess(args, skip_if_plan_to_signal=True)
3955.1.7 by Jonathan Lange
Fix some tests that assumed the port was on stderr rather than stdout.
196
        port_line = process.stderr.readline()
1910.19.7 by Andrew Bennetts
Allow specifying the host/interface to bzr serve, and use the new test
197
        prefix = 'listening on port: '
198
        self.assertStartsWith(port_line, prefix)
199
        port = int(port_line[len(prefix):])
4691.2.1 by Robert Collins
Add stronger test isolation by interception BzrDir.open and checking the thing being opened is known to the test suite.
200
        url = 'bzr://localhost:%d/' % port
201
        self.permit_url(url)
202
        return process, url
5611.1.2 by Jelmer Vernooij
Add some tests for the hooks.
203
4815.3.1 by Gordon Tyler
Added test_bzr_serve_quiet which tests that the output of 'bzr serve --quiet' is really quiet.
204
    def test_bzr_serve_quiet(self):
205
        self.make_branch('.')
4815.3.3 by Gordon Tyler
Changed test_bzr_serve_quiet to use in-process execution of the command.
206
        args = ['--port', 'localhost:0', '--quiet']
207
        out, err = self.run_bzr_serve_then_func(args, retcode=3)
4815.3.2 by Gordon Tyler
test_bzr_serve_quiet should be skipped if signals are not available.
208
        self.assertEqual('', out)
209
        self.assertEqual('', err)
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
210
211
    def test_bzr_serve_inet_readonly(self):
212
        """bzr server should provide a read only filesystem by default."""
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
213
        process, transport = self.start_server_inet()
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
214
        self.assertRaises(errors.TransportNotPossible, transport.mkdir, 'adir')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
215
        self.assertInetServerShutsdownCleanly(process)
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
216
217
    def test_bzr_serve_inet_readwrite(self):
218
        # Make a branch
219
        self.make_branch('.')
220
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
221
        process, transport = self.start_server_inet(['--allow-writes'])
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
222
4911.1.1 by John Arbash Meinel
Threads don't have 'get_ident()' attributes. I think spiv meant 'getName()'.
223
        # We get a working branch, and can create a directory
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
224
        branch = BzrDir.open_from_transport(transport).open_branch()
3287.6.4 by Robert Collins
Fix up deprecation warnings for get_revision_graph.
225
        self.make_read_requests(branch)
4911.1.1 by John Arbash Meinel
Threads don't have 'get_ident()' attributes. I think spiv meant 'getName()'.
226
        transport.mkdir('adir')
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
227
        self.assertInetServerShutsdownCleanly(process)
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
228
229
    def test_bzr_serve_port_readonly(self):
230
        """bzr server should provide a read only filesystem by default."""
231
        process, url = self.start_server_port()
6083.1.1 by Jelmer Vernooij
Use get_transport_from_{url,path} in more places.
232
        t = transport.get_transport_from_url(url)
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
233
        self.assertRaises(errors.TransportNotPossible, t.mkdir, 'adir')
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
234
        self.assertServerFinishesCleanly(process)
235
236
    def test_bzr_serve_port_readwrite(self):
237
        # Make a branch
238
        self.make_branch('.')
239
240
        process, url = self.start_server_port(['--allow-writes'])
1910.19.7 by Andrew Bennetts
Allow specifying the host/interface to bzr serve, and use the new test
241
242
        # Connect to the server
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
243
        branch = Branch.open(url)
3287.6.4 by Robert Collins
Fix up deprecation warnings for get_revision_graph.
244
        self.make_read_requests(branch)
2020.1.1 by Robert Collins
Add readonly support to the smart server, enabled by default via `bzr server`.
245
        self.assertServerFinishesCleanly(process)
1910.19.7 by Andrew Bennetts
Allow specifying the host/interface to bzr serve, and use the new test
246
4370.4.2 by Jelmer Vernooij
Add --protocol option to 'bzr serve'.
247
    def test_bzr_serve_supports_protocol(self):
248
        # Make a branch
249
        self.make_branch('.')
250
251
        process, url = self.start_server_port(['--allow-writes',
252
                                               '--protocol=bzr'])
253
254
        # Connect to the server
255
        branch = Branch.open(url)
256
        self.make_read_requests(branch)
257
        self.assertServerFinishesCleanly(process)
258
4911.1.1 by John Arbash Meinel
Threads don't have 'get_ident()' attributes. I think spiv meant 'getName()'.
259
    def test_bzr_serve_dhpss(self):
260
        # This is a smoke test that the server doesn't crash when run with
261
        # -Dhpss, and does drop some hpss logging to the file.
262
        self.make_branch('.')
263
        log_fname = os.getcwd() + '/server.log'
5570.3.6 by Vincent Ladeuil
Get rid of all _captureVar() calls, no test failures, pfew.
264
        self.overrideEnv('BZR_LOG', log_fname)
4911.1.1 by John Arbash Meinel
Threads don't have 'get_ident()' attributes. I think spiv meant 'getName()'.
265
        process, transport = self.start_server_inet(['-Dhpss'])
266
        branch = BzrDir.open_from_transport(transport).open_branch()
267
        self.make_read_requests(branch)
268
        self.assertInetServerShutsdownCleanly(process)
269
        f = open(log_fname, 'rb')
270
        content = f.read()
271
        f.close()
4913.1.1 by John Arbash Meinel
Switch to using thread.get_ident() which is available on all python versions.
272
        self.assertContainsRe(content, r'hpss request: \[[0-9-]+\]')
4911.1.1 by John Arbash Meinel
Threads don't have 'get_ident()' attributes. I think spiv meant 'getName()'.
273
6133.4.21 by John Arbash Meinel
I'm trying to make sure that 'bzr serve' supports the serve.client_timeout code.
274
    def test_bzr_serve_supports_configurable_timeout(self):
275
        gs = config.GlobalStack()
6133.4.35 by John Arbash Meinel
Change int_from_store into float_from_store, which allows us to set the time under 1.0s.
276
        gs.set('serve.client_timeout', 0.2)
6133.4.21 by John Arbash Meinel
I'm trying to make sure that 'bzr serve' supports the serve.client_timeout code.
277
        process, url = self.start_server_port()
278
        self.build_tree_contents([('a_file', 'contents\n')])
279
        # We can connect and issue a request
280
        t = transport.get_transport_from_url(url)
6133.4.34 by John Arbash Meinel
get the blackbox tests passing.
281
        self.assertEqual('contents\n', t.get_bytes('a_file'))
6133.4.21 by John Arbash Meinel
I'm trying to make sure that 'bzr serve' supports the serve.client_timeout code.
282
        # However, if we just wait for more content from the server, it will
283
        # eventually disconnect us.
6133.4.25 by John Arbash Meinel
Update some test comment.
284
        # TODO: Use something like signal.alarm() so that if the server doesn't
285
        #       properly handle the timeout, we end up failing the test instead
286
        #       of hanging forever.
6133.4.22 by John Arbash Meinel
move the comment
287
        m = t.get_smart_medium()
6133.4.34 by John Arbash Meinel
get the blackbox tests passing.
288
        m.read_bytes(1)
6133.4.21 by John Arbash Meinel
I'm trying to make sure that 'bzr serve' supports the serve.client_timeout code.
289
        # Now, we wait for timeout to trigger
6133.4.34 by John Arbash Meinel
get the blackbox tests passing.
290
        err = process.stderr.readline()
291
        self.assertEqual(
6133.4.35 by John Arbash Meinel
Change int_from_store into float_from_store, which allows us to set the time under 1.0s.
292
            'Connection Timeout: disconnecting client after 0.2 seconds\n',
6133.4.34 by John Arbash Meinel
get the blackbox tests passing.
293
            err)
6133.4.21 by John Arbash Meinel
I'm trying to make sure that 'bzr serve' supports the serve.client_timeout code.
294
        self.assertServerFinishesCleanly(process)
295
6133.4.29 by John Arbash Meinel
Expose --client-timeout to the command line, pass it through the layers.
296
    def test_bzr_serve_supports_client_timeout(self):
297
        process, url = self.start_server_port(['--client-timeout=0.1'])
298
        self.build_tree_contents([('a_file', 'contents\n')])
299
        # We can connect and issue a request
300
        t = transport.get_transport_from_url(url)
6133.4.34 by John Arbash Meinel
get the blackbox tests passing.
301
        self.assertEqual('contents\n', t.get_bytes('a_file'))
6133.4.29 by John Arbash Meinel
Expose --client-timeout to the command line, pass it through the layers.
302
        # However, if we just wait for more content from the server, it will
303
        # eventually disconnect us.
304
        # TODO: Use something like signal.alarm() so that if the server doesn't
305
        #       properly handle the timeout, we end up failing the test instead
306
        #       of hanging forever.
307
        m = t.get_smart_medium()
6133.4.34 by John Arbash Meinel
get the blackbox tests passing.
308
        m.read_bytes(1)
6133.4.29 by John Arbash Meinel
Expose --client-timeout to the command line, pass it through the layers.
309
        # Now, we wait for timeout to trigger
6133.4.34 by John Arbash Meinel
get the blackbox tests passing.
310
        err = process.stderr.readline()
311
        self.assertEqual(
312
            'Connection Timeout: disconnecting client after 0.1 seconds\n',
313
            err)
6133.4.29 by John Arbash Meinel
Expose --client-timeout to the command line, pass it through the layers.
314
        self.assertServerFinishesCleanly(process)
315
6133.4.47 by John Arbash Meinel
Testing that 'bzr serve' actually installs SIGHUP and responds to it showed some problems.
316
    def test_bzr_serve_graceful_shutdown(self):
6133.4.68 by John Arbash Meinel
Fix the blackbox test to wait for the process to exit.
317
        big_contents = 'a'*64*1024
318
        self.build_tree_contents([('bigfile', big_contents)])
6133.4.47 by John Arbash Meinel
Testing that 'bzr serve' actually installs SIGHUP and responds to it showed some problems.
319
        process, url = self.start_server_port(['--client-timeout=1.0'])
320
        t = transport.get_transport_from_url(url)
6133.4.68 by John Arbash Meinel
Fix the blackbox test to wait for the process to exit.
321
        m = t.get_smart_medium()
322
        c = client._SmartClient(m)
323
        # Start, but don't finish a response
324
        resp, response_handler = c.call_expecting_body('get', 'bigfile')
325
        self.assertEqual(('ok',), resp)
6133.4.47 by John Arbash Meinel
Testing that 'bzr serve' actually installs SIGHUP and responds to it showed some problems.
326
        # Note: process.send_signal is a Python 2.6ism
327
        process.send_signal(signal.SIGHUP)
6133.4.68 by John Arbash Meinel
Fix the blackbox test to wait for the process to exit.
328
        # Wait for the server to notice the signal, and then read the actual
329
        # body of the response. That way we know that it is waiting for the
330
        # request to finish
331
        self.assertEqual('Requested to stop gracefully\n',
332
                         process.stderr.readline())
333
        self.assertEqual('Waiting for 1 client(s) to finish\n',
334
                         process.stderr.readline())
335
        body = response_handler.read_body_bytes()
336
        if body != big_contents:
337
            self.fail('Failed to properly read the contents of "bigfile"')
338
        # Now that our request is finished, the medium should notice it has
339
        # been disconnected.
6133.4.47 by John Arbash Meinel
Testing that 'bzr serve' actually installs SIGHUP and responds to it showed some problems.
340
        self.assertEqual('', m.read_bytes(1))
6133.4.68 by John Arbash Meinel
Fix the blackbox test to wait for the process to exit.
341
        # And the server should be stopping
342
        self.assertEqual(0, process.wait())
6133.4.47 by John Arbash Meinel
Testing that 'bzr serve' actually installs SIGHUP and responds to it showed some problems.
343
4544.1.2 by Andrew Bennetts
Add test that would catch the lack of ChrootServer in cmd_serve.
344
4815.3.7 by Gordon Tyler
Made a few changes at the suggestion of vila.
345
class TestCmdServeChrooting(TestBzrServeBase):
4544.1.2 by Andrew Bennetts
Add test that would catch the lack of ChrootServer in cmd_serve.
346
347
    def test_serve_tcp(self):
348
        """'bzr serve' wraps the given --directory in a ChrootServer.
349
350
        So requests that search up through the parent directories (like
351
        find_repositoryV3) will give "not found" responses, rather than
352
        InvalidURLJoin or jail break errors.
353
        """
354
        t = self.get_transport()
355
        t.mkdir('server-root')
356
        self.run_bzr_serve_then_func(
4676.3.3 by Vincent Ladeuil
Force IPV4 to fix failure on IPV6-enabled hosts.
357
            ['--port', '127.0.0.1:0',
358
             '--directory', t.local_abspath('server-root'),
4544.1.2 by Andrew Bennetts
Add test that would catch the lack of ChrootServer in cmd_serve.
359
             '--allow-writes'],
4815.3.3 by Gordon Tyler
Changed test_bzr_serve_quiet to use in-process execution of the command.
360
            func=self.when_server_started)
4544.1.2 by Andrew Bennetts
Add test that would catch the lack of ChrootServer in cmd_serve.
361
        # The when_server_started method issued a find_repositoryV3 that should
362
        # fail with 'norepository' because there are no repositories inside the
363
        # --directory.
4676.3.3 by Vincent Ladeuil
Force IPV4 to fix failure on IPV6-enabled hosts.
364
        self.assertEqual(('norepository',), self.client_resp)
4676.3.1 by Vincent Ladeuil
Marking TestCmdServeChrooting.test_serve_tcp as expected failure
365
4544.1.2 by Andrew Bennetts
Add test that would catch the lack of ChrootServer in cmd_serve.
366
    def when_server_started(self):
367
        # Connect to the TCP server and issue some requests and see what comes
368
        # back.
369
        client_medium = medium.SmartTCPClientMedium(
370
            '127.0.0.1', self.tcp_server.port,
371
            'bzr://localhost:%d/' % (self.tcp_server.port,))
372
        smart_client = client._SmartClient(client_medium)
373
        resp = smart_client.call('mkdir', 'foo', '')
374
        resp = smart_client.call('BzrDirFormat.initialize', 'foo/')
375
        try:
376
            resp = smart_client.call('BzrDir.find_repositoryV3', 'foo/')
377
        except errors.ErrorFromSmartServer, e:
378
            resp = e.error_tuple
379
        self.client_resp = resp
380
        client_medium.disconnect()
381
382
4634.43.7 by Andrew Bennetts
Add some unit tests for parts of userdir expansion.
383
class TestUserdirExpansion(TestCaseWithMemoryTransport):
384
5340.15.1 by John Arbash Meinel
supersede exc-info branch
385
    @staticmethod
386
    def fake_expanduser(path):
4634.43.7 by Andrew Bennetts
Add some unit tests for parts of userdir expansion.
387
        """A simple, environment-independent, function for the duration of this
388
        test.
389
390
        Paths starting with a path segment of '~user' will expand to start with
391
        '/home/user/'.  Every other path will be unchanged.
392
        """
393
        if path.split('/', 1)[0] == '~user':
394
            return '/home/user' + path[len('~user'):]
395
        return path
396
397
    def make_test_server(self, base_path='/'):
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
398
        """Make and start a BzrServerFactory, backed by a memory transport, and
4634.43.7 by Andrew Bennetts
Add some unit tests for parts of userdir expansion.
399
        creat '/home/user' in that transport.
400
        """
4634.43.15 by Andrew Bennetts
Rename BzrServerMaker -> BzrServerFactory.
401
        bzr_server = BzrServerFactory(
4634.43.7 by Andrew Bennetts
Add some unit tests for parts of userdir expansion.
402
            self.fake_expanduser, lambda t: base_path)
403
        mem_transport = self.get_transport()
404
        mem_transport.mkdir_multi(['home', 'home/user'])
6133.4.34 by John Arbash Meinel
get the blackbox tests passing.
405
        bzr_server.set_up(mem_transport, None, None, inet=True, timeout=4.0)
4634.43.19 by Andrew Bennetts
Rename BzrServerFactory's setUp/tearDown to set_up/tear_down; this isn't a TestCase (or transport Server), so we should not use camelCase names.
406
        self.addCleanup(bzr_server.tear_down)
4634.43.7 by Andrew Bennetts
Add some unit tests for parts of userdir expansion.
407
        return bzr_server
408
409
    def test_bzr_serve_expands_userdir(self):
410
        bzr_server = self.make_test_server()
411
        self.assertTrue(bzr_server.smart_server.backing_transport.has('~user'))
412
413
    def test_bzr_serve_does_not_expand_userdir_outside_base(self):
414
        bzr_server = self.make_test_server('/foo')
415
        self.assertFalse(bzr_server.smart_server.backing_transport.has('~user'))
4544.1.2 by Andrew Bennetts
Add test that would catch the lack of ChrootServer in cmd_serve.
416
4634.43.8 by Andrew Bennetts
Test for recovering the --directory value from the transport cmd_serve passes to bzr_serve.
417
    def test_get_base_path(self):
418
        """cmd_serve will turn the --directory option into a LocalTransport
4634.43.15 by Andrew Bennetts
Rename BzrServerMaker -> BzrServerFactory.
419
        (optionally decorated with 'readonly+').  BzrServerFactory can
420
        determine the original --directory from that transport.
4634.43.8 by Andrew Bennetts
Test for recovering the --directory value from the transport cmd_serve passes to bzr_serve.
421
        """
4797.3.4 by John Arbash Meinel
Per review recommendation, use 'osutils.abspath' instead of hardcoded string.
422
        # URLs always include the trailing slash, and get_base_path returns it
423
        base_dir = osutils.abspath('/a/b/c') + '/'
4797.3.21 by John Arbash Meinel
Use urlutils.local_path_to_url to handle both windows and linux.
424
        base_url = urlutils.local_path_to_url(base_dir) + '/'
4634.43.8 by Andrew Bennetts
Test for recovering the --directory value from the transport cmd_serve passes to bzr_serve.
425
        # Define a fake 'protocol' to capture the transport that cmd_serve
426
        # passes to serve_bzr.
6133.4.34 by John Arbash Meinel
get the blackbox tests passing.
427
        def capture_transport(transport, host, port, inet, timeout):
4634.43.8 by Andrew Bennetts
Test for recovering the --directory value from the transport cmd_serve passes to bzr_serve.
428
            self.bzr_serve_transport = transport
429
        cmd = builtins.cmd_serve()
430
        # Read-only
4789.7.1 by John Arbash Meinel
Fix a 'bzr serve' test that didn't expect windows translating '/a' to 'C:/a'.
431
        cmd.run(directory=base_dir, protocol=capture_transport)
4634.43.15 by Andrew Bennetts
Rename BzrServerMaker -> BzrServerFactory.
432
        server_maker = BzrServerFactory()
4634.43.8 by Andrew Bennetts
Test for recovering the --directory value from the transport cmd_serve passes to bzr_serve.
433
        self.assertEqual(
4797.3.21 by John Arbash Meinel
Use urlutils.local_path_to_url to handle both windows and linux.
434
            'readonly+%s' % base_url, self.bzr_serve_transport.base)
4634.43.8 by Andrew Bennetts
Test for recovering the --directory value from the transport cmd_serve passes to bzr_serve.
435
        self.assertEqual(
4789.7.1 by John Arbash Meinel
Fix a 'bzr serve' test that didn't expect windows translating '/a' to 'C:/a'.
436
            base_dir, server_maker.get_base_path(self.bzr_serve_transport))
4634.43.8 by Andrew Bennetts
Test for recovering the --directory value from the transport cmd_serve passes to bzr_serve.
437
        # Read-write
4789.7.1 by John Arbash Meinel
Fix a 'bzr serve' test that didn't expect windows translating '/a' to 'C:/a'.
438
        cmd.run(directory=base_dir, protocol=capture_transport,
4634.43.8 by Andrew Bennetts
Test for recovering the --directory value from the transport cmd_serve passes to bzr_serve.
439
            allow_writes=True)
4634.43.15 by Andrew Bennetts
Rename BzrServerMaker -> BzrServerFactory.
440
        server_maker = BzrServerFactory()
4797.3.21 by John Arbash Meinel
Use urlutils.local_path_to_url to handle both windows and linux.
441
        self.assertEqual(base_url, self.bzr_serve_transport.base)
4789.7.1 by John Arbash Meinel
Fix a 'bzr serve' test that didn't expect windows translating '/a' to 'C:/a'.
442
        self.assertEqual(base_dir,
443
            server_maker.get_base_path(self.bzr_serve_transport))
6236.1.1 by Jelmer Vernooij
bzr serve can now serve remote URLs and things behind directory services.
444
        # Read-only, from a URL
445
        cmd.run(directory=base_url, protocol=capture_transport)
446
        server_maker = BzrServerFactory()
447
        self.assertEqual(
448
            'readonly+%s' % base_url, self.bzr_serve_transport.base)
449
        self.assertEqual(
450
            base_dir, server_maker.get_base_path(self.bzr_serve_transport))