/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
6133.4.44 by John Arbash Meinel
Move the code into bzrlib.smart.signals.
1
# Copyright (C) 2011 Canonical Ltd
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
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
17
6133.4.61 by John Arbash Meinel
Expose infrastructure so that we can test the Inet portion of the server.
18
import os
6133.4.44 by John Arbash Meinel
Move the code into bzrlib.smart.signals.
19
import signal
6133.4.61 by John Arbash Meinel
Expose infrastructure so that we can test the Inet portion of the server.
20
import threading
6133.4.44 by John Arbash Meinel
Move the code into bzrlib.smart.signals.
21
import weakref
22
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
23
from breezy import tests, transport
6670.4.16 by Jelmer Vernooij
Move smart to breezy.bzr.
24
from breezy.bzr.smart import client, medium, server, signals
6133.4.44 by John Arbash Meinel
Move the code into bzrlib.smart.signals.
25
6133.4.48 by John Arbash Meinel
Some win32 specific tweaks.
26
# Windows doesn't define SIGHUP. And while we could just skip a lot of these
27
# tests, we often don't actually care about interaction with 'signal', so we
28
# can still run the tests for code coverage.
29
SIGHUP = getattr(signal, 'SIGHUP', 1)
30
6133.4.44 by John Arbash Meinel
Move the code into bzrlib.smart.signals.
31
32
class TestSignalHandlers(tests.TestCase):
33
34
    def setUp(self):
35
        super(TestSignalHandlers, self).setUp()
36
        # This allows us to mutate the signal handler callbacks, but leave it
37
        # 'pristine' after the test case.
38
        # TODO: Arguably, this could be put into the base test.TestCase, along
39
        #       with a tearDown that asserts that all the entries have been
40
        #       removed properly. Global state is always a bit messy. A shame
41
        #       that we need it for signal handling.
6133.4.45 by John Arbash Meinel
Change the code a bit.
42
        orig = signals._setup_on_hangup_dict()
43
        self.assertIs(None, orig)
7143.15.2 by Jelmer Vernooij
Run autopep8.
44
6133.4.45 by John Arbash Meinel
Change the code a bit.
45
        def cleanup():
46
            signals._on_sighup = None
47
        self.addCleanup(cleanup)
6133.4.44 by John Arbash Meinel
Move the code into bzrlib.smart.signals.
48
49
    def test_registered_callback_gets_called(self):
50
        calls = []
7143.15.2 by Jelmer Vernooij
Run autopep8.
51
6133.4.44 by John Arbash Meinel
Move the code into bzrlib.smart.signals.
52
        def call_me():
53
            calls.append('called')
54
        signals.register_on_hangup('myid', call_me)
6133.4.48 by John Arbash Meinel
Some win32 specific tweaks.
55
        signals._sighup_handler(SIGHUP, None)
6133.4.44 by John Arbash Meinel
Move the code into bzrlib.smart.signals.
56
        self.assertEqual(['called'], calls)
57
        signals.unregister_on_hangup('myid')
58
59
    def test_unregister_not_present(self):
60
        # We don't want unregister to fail, since it is generally run at times
61
        # that shouldn't interrupt other flow.
62
        signals.unregister_on_hangup('no-such-id')
63
        log = self.get_log()
7143.15.2 by Jelmer Vernooij
Run autopep8.
64
        self.assertContainsRe(
65
            log, 'Error occurred during unregister_on_hangup:')
6133.4.44 by John Arbash Meinel
Move the code into bzrlib.smart.signals.
66
        self.assertContainsRe(log, '(?s)Traceback.*KeyError')
67
68
    def test_failing_callback(self):
69
        calls = []
7143.15.2 by Jelmer Vernooij
Run autopep8.
70
6133.4.44 by John Arbash Meinel
Move the code into bzrlib.smart.signals.
71
        def call_me():
72
            calls.append('called')
7143.15.2 by Jelmer Vernooij
Run autopep8.
73
6133.4.44 by John Arbash Meinel
Move the code into bzrlib.smart.signals.
74
        def fail_me():
75
            raise RuntimeError('something bad happened')
76
        signals.register_on_hangup('myid', call_me)
77
        signals.register_on_hangup('otherid', fail_me)
78
        # _sighup_handler should call both, even though it got an exception
6133.4.48 by John Arbash Meinel
Some win32 specific tweaks.
79
        signals._sighup_handler(SIGHUP, None)
6133.4.44 by John Arbash Meinel
Move the code into bzrlib.smart.signals.
80
        signals.unregister_on_hangup('myid')
81
        signals.unregister_on_hangup('otherid')
82
        log = self.get_log()
83
        self.assertContainsRe(log, '(?s)Traceback.*RuntimeError')
84
        self.assertEqual(['called'], calls)
85
86
    def test_unregister_during_call(self):
87
        # _sighup_handler should handle if some callbacks actually remove
88
        # themselves while running.
89
        calls = []
7143.15.2 by Jelmer Vernooij
Run autopep8.
90
6133.4.44 by John Arbash Meinel
Move the code into bzrlib.smart.signals.
91
        def call_me_and_unregister():
92
            signals.unregister_on_hangup('myid')
93
            calls.append('called_and_unregistered')
7143.15.2 by Jelmer Vernooij
Run autopep8.
94
6133.4.44 by John Arbash Meinel
Move the code into bzrlib.smart.signals.
95
        def call_me():
96
            calls.append('called')
97
        signals.register_on_hangup('myid', call_me_and_unregister)
98
        signals.register_on_hangup('other', call_me)
6133.4.48 by John Arbash Meinel
Some win32 specific tweaks.
99
        signals._sighup_handler(SIGHUP, None)
6133.4.44 by John Arbash Meinel
Move the code into bzrlib.smart.signals.
100
101
    def test_keyboard_interrupt_propagated(self):
102
        # In case we get 'stuck' while running a hangup function, we should
103
        # not suppress KeyboardInterrupt
104
        def call_me_and_raise():
105
            raise KeyboardInterrupt()
106
        signals.register_on_hangup('myid', call_me_and_raise)
107
        self.assertRaises(KeyboardInterrupt,
6133.4.48 by John Arbash Meinel
Some win32 specific tweaks.
108
                          signals._sighup_handler, SIGHUP, None)
6133.4.44 by John Arbash Meinel
Move the code into bzrlib.smart.signals.
109
        signals.unregister_on_hangup('myid')
110
111
    def test_weak_references(self):
112
        # TODO: This is probably a very-CPython-specific test
113
        # Adding yourself to the callback should not make you immortal
114
        # We overrideAttr during the test suite, so that we don't pollute the
115
        # original dict. However, we can test that what we override matches
116
        # what we are putting there.
6133.4.45 by John Arbash Meinel
Change the code a bit.
117
        self.assertIsInstance(signals._on_sighup,
6133.4.44 by John Arbash Meinel
Move the code into bzrlib.smart.signals.
118
                              weakref.WeakValueDictionary)
119
        calls = []
7143.15.2 by Jelmer Vernooij
Run autopep8.
120
6133.4.44 by John Arbash Meinel
Move the code into bzrlib.smart.signals.
121
        def call_me():
122
            calls.append('called')
123
        signals.register_on_hangup('myid', call_me)
124
        del call_me
6133.4.45 by John Arbash Meinel
Change the code a bit.
125
        # Non-CPython might want to do a gc.collect() here
6133.4.48 by John Arbash Meinel
Some win32 specific tweaks.
126
        signals._sighup_handler(SIGHUP, None)
6133.4.44 by John Arbash Meinel
Move the code into bzrlib.smart.signals.
127
        self.assertEqual([], calls)
6133.4.45 by John Arbash Meinel
Change the code a bit.
128
129
    def test_not_installed(self):
6670.4.16 by Jelmer Vernooij
Move smart to breezy.bzr.
130
        # If you haven't called breezy.bzr.smart.signals.install_sighup_handler,
6133.4.45 by John Arbash Meinel
Change the code a bit.
131
        # then _on_sighup should be None, and all the calls become no-ops.
132
        signals._on_sighup = None
133
        calls = []
7143.15.2 by Jelmer Vernooij
Run autopep8.
134
6133.4.45 by John Arbash Meinel
Change the code a bit.
135
        def call_me():
136
            calls.append('called')
137
        signals.register_on_hangup('myid', calls)
6133.4.48 by John Arbash Meinel
Some win32 specific tweaks.
138
        signals._sighup_handler(SIGHUP, None)
6133.4.45 by John Arbash Meinel
Change the code a bit.
139
        signals.unregister_on_hangup('myid')
140
        log = self.get_log()
141
        self.assertEqual('', log)
6133.4.46 by John Arbash Meinel
Test that signals.install_sighup_handler does what we want.
142
143
    def test_install_sighup_handler(self):
144
        # install_sighup_handler should set up a signal handler for SIGHUP, as
145
        # well as the signals._on_sighup dict.
146
        signals._on_sighup = None
147
        orig = signals.install_sighup_handler()
6133.4.60 by John Arbash Meinel
serve_bzr wasn't properly cleaning up the new _on_sighup dict, etc.
148
        if getattr(signal, 'SIGHUP', None) is not None:
6133.4.67 by John Arbash Meinel
Jelmer caught that getsignal() only takes one parameter.
149
            cur = signal.getsignal(SIGHUP)
6133.4.60 by John Arbash Meinel
serve_bzr wasn't properly cleaning up the new _on_sighup dict, etc.
150
            self.assertEqual(signals._sighup_handler, cur)
6133.4.46 by John Arbash Meinel
Test that signals.install_sighup_handler does what we want.
151
        self.assertIsNot(None, signals._on_sighup)
6133.4.60 by John Arbash Meinel
serve_bzr wasn't properly cleaning up the new _on_sighup dict, etc.
152
        signals.restore_sighup_handler(orig)
153
        self.assertIs(None, signals._on_sighup)
6133.4.61 by John Arbash Meinel
Expose infrastructure so that we can test the Inet portion of the server.
154
155
156
class TestInetServer(tests.TestCase):
157
158
    def create_file_pipes(self):
159
        r, w = os.pipe()
160
        rf = os.fdopen(r, 'rb')
161
        wf = os.fdopen(w, 'wb')
162
        return rf, wf
163
164
    def test_inet_server_responds_to_sighup(self):
165
        t = transport.get_transport('memory:///')
7143.15.2 by Jelmer Vernooij
Run autopep8.
166
        content = b'a' * 1024 * 1024
6133.4.61 by John Arbash Meinel
Expose infrastructure so that we can test the Inet portion of the server.
167
        t.put_bytes('bigfile', content)
168
        factory = server.BzrServerFactory()
169
        # Override stdin/stdout so that we can inject our own handles
170
        client_read, server_write = self.create_file_pipes()
171
        server_read, client_write = self.create_file_pipes()
172
        factory._get_stdin_stdout = lambda: (server_read, server_write)
173
        factory.set_up(t, None, None, inet=True, timeout=4.0)
174
        self.addCleanup(factory.tear_down)
175
        started = threading.Event()
176
        stopped = threading.Event()
7143.15.2 by Jelmer Vernooij
Run autopep8.
177
6133.4.61 by John Arbash Meinel
Expose infrastructure so that we can test the Inet portion of the server.
178
        def serving():
179
            started.set()
180
            factory.smart_server.serve()
181
            stopped.set()
182
        server_thread = threading.Thread(target=serving)
183
        server_thread.start()
184
        started.wait()
185
        client_medium = medium.SmartSimplePipesClientMedium(client_read,
7143.15.2 by Jelmer Vernooij
Run autopep8.
186
                                                            client_write, 'base')
6133.4.61 by John Arbash Meinel
Expose infrastructure so that we can test the Inet portion of the server.
187
        client_client = client._SmartClient(client_medium)
7063.1.1 by Jelmer Vernooij
Fix flaky test.
188
        resp, response_handler = client_client.call_expecting_body(b'get',
7143.15.2 by Jelmer Vernooij
Run autopep8.
189
                                                                   b'bigfile')
6133.4.61 by John Arbash Meinel
Expose infrastructure so that we can test the Inet portion of the server.
190
        signals._sighup_handler(SIGHUP, None)
191
        self.assertTrue(factory.smart_server.finished)
192
        # We can still finish reading the file content, but more than that, and
193
        # the file is closed.
194
        v = response_handler.read_body_bytes()
195
        if v != content:
196
            self.fail('Got the wrong content back, expected 1M "a"')
197
        stopped.wait()
198
        server_thread.join()