~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

(jameinel) Allow 'bzr serve' to interpret SIGHUP as a graceful shutdown.
 (bug #795025) (John A Meinel)

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
import sys
23
23
import thread
24
24
import threading
 
25
import time
25
26
 
26
27
from bzrlib import (
27
28
    builtins,
 
29
    config,
28
30
    errors,
29
31
    osutils,
30
32
    revision as _mod_revision,
66
68
            try:
67
69
                # Run func if set
68
70
                self.tcp_server = tcp_server
69
 
                if not func is None:
 
71
                if func is not None:
70
72
                    try:
71
73
                        func(*func_args, **func_kwargs)
72
74
                    except Exception, e:
87
89
        SmartTCPServer.hooks.install_named_hook(
88
90
            'server_started_ex', on_server_start,
89
91
            'run_bzr_serve_then_func hook')
 
92
        # It seesm thread.interrupt_main() will not raise KeyboardInterrupt
 
93
        # until after socket.accept returns. So we set the timeout low to make
 
94
        # the test faster.
 
95
        self.overrideAttr(SmartTCPServer, '_ACCEPT_TIMEOUT', 0.1)
90
96
        # start a TCP server
91
97
        try:
92
98
            out, err = self.run_bzr(['serve'] + list(serve_args),
266
272
        f.close()
267
273
        self.assertContainsRe(content, r'hpss request: \[[0-9-]+\]')
268
274
 
 
275
    def test_bzr_serve_supports_configurable_timeout(self):
 
276
        gs = config.GlobalStack()
 
277
        gs.set('serve.client_timeout', 0.2)
 
278
        process, url = self.start_server_port()
 
279
        self.build_tree_contents([('a_file', 'contents\n')])
 
280
        # We can connect and issue a request
 
281
        t = transport.get_transport_from_url(url)
 
282
        self.assertEqual('contents\n', t.get_bytes('a_file'))
 
283
        # However, if we just wait for more content from the server, it will
 
284
        # eventually disconnect us.
 
285
        # TODO: Use something like signal.alarm() so that if the server doesn't
 
286
        #       properly handle the timeout, we end up failing the test instead
 
287
        #       of hanging forever.
 
288
        m = t.get_smart_medium()
 
289
        m.read_bytes(1)
 
290
        # Now, we wait for timeout to trigger
 
291
        err = process.stderr.readline()
 
292
        self.assertEqual(
 
293
            'Connection Timeout: disconnecting client after 0.2 seconds\n',
 
294
            err)
 
295
        self.assertServerFinishesCleanly(process)
 
296
 
 
297
    def test_bzr_serve_supports_client_timeout(self):
 
298
        process, url = self.start_server_port(['--client-timeout=0.1'])
 
299
        self.build_tree_contents([('a_file', 'contents\n')])
 
300
        # We can connect and issue a request
 
301
        t = transport.get_transport_from_url(url)
 
302
        self.assertEqual('contents\n', t.get_bytes('a_file'))
 
303
        # However, if we just wait for more content from the server, it will
 
304
        # eventually disconnect us.
 
305
        # TODO: Use something like signal.alarm() so that if the server doesn't
 
306
        #       properly handle the timeout, we end up failing the test instead
 
307
        #       of hanging forever.
 
308
        m = t.get_smart_medium()
 
309
        m.read_bytes(1)
 
310
        # Now, we wait for timeout to trigger
 
311
        err = process.stderr.readline()
 
312
        self.assertEqual(
 
313
            'Connection Timeout: disconnecting client after 0.1 seconds\n',
 
314
            err)
 
315
        self.assertServerFinishesCleanly(process)
 
316
 
 
317
    def test_bzr_serve_graceful_shutdown(self):
 
318
        big_contents = 'a'*64*1024
 
319
        self.build_tree_contents([('bigfile', big_contents)])
 
320
        process, url = self.start_server_port(['--client-timeout=1.0'])
 
321
        t = transport.get_transport_from_url(url)
 
322
        m = t.get_smart_medium()
 
323
        c = client._SmartClient(m)
 
324
        # Start, but don't finish a response
 
325
        resp, response_handler = c.call_expecting_body('get', 'bigfile')
 
326
        self.assertEqual(('ok',), resp)
 
327
        # Note: process.send_signal is a Python 2.6ism
 
328
        process.send_signal(signal.SIGHUP)
 
329
        # Wait for the server to notice the signal, and then read the actual
 
330
        # body of the response. That way we know that it is waiting for the
 
331
        # request to finish
 
332
        self.assertEqual('Requested to stop gracefully\n',
 
333
                         process.stderr.readline())
 
334
        self.assertEqual('Waiting for 1 client(s) to finish\n',
 
335
                         process.stderr.readline())
 
336
        body = response_handler.read_body_bytes()
 
337
        if body != big_contents:
 
338
            self.fail('Failed to properly read the contents of "bigfile"')
 
339
        # Now that our request is finished, the medium should notice it has
 
340
        # been disconnected.
 
341
        self.assertEqual('', m.read_bytes(1))
 
342
        # And the server should be stopping
 
343
        self.assertEqual(0, process.wait())
 
344
 
269
345
 
270
346
class TestCmdServeChrooting(TestBzrServeBase):
271
347
 
327
403
            self.fake_expanduser, lambda t: base_path)
328
404
        mem_transport = self.get_transport()
329
405
        mem_transport.mkdir_multi(['home', 'home/user'])
330
 
        bzr_server.set_up(mem_transport, None, None, inet=True)
 
406
        bzr_server.set_up(mem_transport, None, None, inet=True, timeout=4.0)
331
407
        self.addCleanup(bzr_server.tear_down)
332
408
        return bzr_server
333
409
 
349
425
        base_url = urlutils.local_path_to_url(base_dir) + '/'
350
426
        # Define a fake 'protocol' to capture the transport that cmd_serve
351
427
        # passes to serve_bzr.
352
 
        def capture_transport(transport, host, port, inet):
 
428
        def capture_transport(transport, host, port, inet, timeout):
353
429
            self.bzr_serve_transport = transport
354
430
        cmd = builtins.cmd_serve()
355
431
        # Read-only