/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
4986.2.1 by Martin Pool
Remove tearDown in tests in favor of addCleanup
1
# Copyright (C) 2009, 2010 Canonical Ltd
3990.3.2 by Andrew Bennetts
Fix the do_body NotImplementedError log spam.
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
3990.3.2 by Andrew Bennetts
Fix the do_body NotImplementedError log spam.
16
6670.4.16 by Jelmer Vernooij
Move smart to breezy.bzr.
17
"""Tests for smart server request infrastructure (breezy.bzr.smart.request)."""
3990.3.2 by Andrew Bennetts
Fix the do_body NotImplementedError log spam.
18
4160.2.2 by Andrew Bennetts
Add setup_jail and teardown_jail to SmartServerRequest.
19
import threading
20
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
21
from breezy import (
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
22
    errors,
23
    transport,
24
    )
6670.4.1 by Jelmer Vernooij
Update imports.
25
from breezy.bzr.bzrdir import BzrDir
6670.4.16 by Jelmer Vernooij
Move smart to breezy.bzr.
26
from breezy.bzr.smart import request
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
27
from breezy.tests import TestCase, TestCaseWithMemoryTransport
3990.3.2 by Andrew Bennetts
Fix the do_body NotImplementedError log spam.
28
29
3990.3.3 by Andrew Bennetts
Add a test that unexpected request bodies trigger a SmartProtocolError from request implementations.
30
class NoBodyRequest(request.SmartServerRequest):
31
    """A request that does not implement do_body."""
32
33
    def do(self):
34
        return request.SuccessfulSmartServerResponse(('ok',))
35
36
4144.3.1 by Andrew Bennetts
Add Repository.insert_stream_locked server-side implementation, plus tests for server-side _translate_error.
37
class DoErrorRequest(request.SmartServerRequest):
38
    """A request that raises an error from self.do()."""
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
39
4144.3.1 by Andrew Bennetts
Add Repository.insert_stream_locked server-side implementation, plus tests for server-side _translate_error.
40
    def do(self):
41
        raise errors.NoSuchFile('xyzzy')
42
43
5677.2.8 by Martin
More tests for handling of unexpected remote errors
44
class DoUnexpectedErrorRequest(request.SmartServerRequest):
45
    """A request that encounters a generic error in self.do()"""
46
47
    def do(self):
48
        dict()[1]
49
50
4144.3.1 by Andrew Bennetts
Add Repository.insert_stream_locked server-side implementation, plus tests for server-side _translate_error.
51
class ChunkErrorRequest(request.SmartServerRequest):
52
    """A request that raises an error from self.do_chunk()."""
7143.15.2 by Jelmer Vernooij
Run autopep8.
53
4144.3.1 by Andrew Bennetts
Add Repository.insert_stream_locked server-side implementation, plus tests for server-side _translate_error.
54
    def do(self):
55
        """No-op."""
56
        pass
57
58
    def do_chunk(self, bytes):
59
        raise errors.NoSuchFile('xyzzy')
60
61
62
class EndErrorRequest(request.SmartServerRequest):
63
    """A request that raises an error from self.do_end()."""
7143.15.2 by Jelmer Vernooij
Run autopep8.
64
4144.3.1 by Andrew Bennetts
Add Repository.insert_stream_locked server-side implementation, plus tests for server-side _translate_error.
65
    def do(self):
66
        """No-op."""
67
        pass
68
69
    def do_chunk(self, bytes):
70
        """No-op."""
71
        pass
7143.15.2 by Jelmer Vernooij
Run autopep8.
72
4144.3.1 by Andrew Bennetts
Add Repository.insert_stream_locked server-side implementation, plus tests for server-side _translate_error.
73
    def do_end(self):
74
        raise errors.NoSuchFile('xyzzy')
75
76
4160.2.2 by Andrew Bennetts
Add setup_jail and teardown_jail to SmartServerRequest.
77
class CheckJailRequest(request.SmartServerRequest):
78
79
    def __init__(self, *args):
80
        request.SmartServerRequest.__init__(self, *args)
81
        self.jail_transports_log = []
82
83
    def do(self):
84
        self.jail_transports_log.append(request.jail_info.transports)
85
86
    def do_chunk(self, bytes):
87
        self.jail_transports_log.append(request.jail_info.transports)
88
89
    def do_end(self):
90
        self.jail_transports_log.append(request.jail_info.transports)
91
92
6734.1.22 by Jelmer Vernooij
review comments.
93
class TestErrors(TestCase):
6734.1.4 by Jelmer Vernooij
Move DisabledMethod.
94
95
    def test_disabled_method(self):
96
        error = request.DisabledMethod("class name")
97
        self.assertEqualDiff(
98
            "The smart server method 'class name' is disabled.", str(error))
99
100
3990.3.2 by Andrew Bennetts
Fix the do_body NotImplementedError log spam.
101
class TestSmartRequest(TestCase):
102
103
    def test_request_class_without_do_body(self):
104
        """If a request has no body data, and the request's implementation does
105
        not override do_body, then no exception is raised.
106
        """
107
        # Create a SmartServerRequestHandler with a SmartServerRequest subclass
108
        # that does not implement do_body.
109
        handler = request.SmartServerRequestHandler(
6963.1.2 by Jelmer Vernooij
Fix some more tests.
110
            None, {b'foo': NoBodyRequest}, '/')
3990.3.2 by Andrew Bennetts
Fix the do_body NotImplementedError log spam.
111
        # Emulate a request with no body (i.e. just args).
6963.1.1 by Jelmer Vernooij
Fix a bunch of tests on python3.
112
        handler.args_received((b'foo',))
3990.3.2 by Andrew Bennetts
Fix the do_body NotImplementedError log spam.
113
        handler.end_received()
3990.3.3 by Andrew Bennetts
Add a test that unexpected request bodies trigger a SmartProtocolError from request implementations.
114
        # Request done, no exception was raised.
115
4160.2.2 by Andrew Bennetts
Add setup_jail and teardown_jail to SmartServerRequest.
116
    def test_only_request_code_is_jailed(self):
117
        transport = 'dummy transport'
118
        handler = request.SmartServerRequestHandler(
6963.1.2 by Jelmer Vernooij
Fix some more tests.
119
            transport, {b'foo': CheckJailRequest}, '/')
6963.1.1 by Jelmer Vernooij
Fix a bunch of tests on python3.
120
        handler.args_received((b'foo',))
4160.2.2 by Andrew Bennetts
Add setup_jail and teardown_jail to SmartServerRequest.
121
        self.assertEqual(None, request.jail_info.transports)
6963.1.1 by Jelmer Vernooij
Fix a bunch of tests on python3.
122
        handler.accept_body(b'bytes')
4160.2.2 by Andrew Bennetts
Add setup_jail and teardown_jail to SmartServerRequest.
123
        self.assertEqual(None, request.jail_info.transports)
124
        handler.end_received()
125
        self.assertEqual(None, request.jail_info.transports)
126
        self.assertEqual(
127
            [[transport]] * 3, handler._command.jail_transports_log)
128
4797.85.31 by John Arbash Meinel
Categorize all of the requests as safe/unsafe/semi/stream for retrying purposes.
129
    def test_all_registered_requests_are_safety_qualified(self):
130
        unclassified_requests = []
4797.85.32 by John Arbash Meinel
Per request, change
131
        allowed_info = ('read', 'idem', 'mutate', 'semivfs', 'semi', 'stream')
4797.85.31 by John Arbash Meinel
Categorize all of the requests as safe/unsafe/semi/stream for retrying purposes.
132
        for key in request.request_handlers.keys():
133
            info = request.request_handlers.get_info(key)
4797.85.32 by John Arbash Meinel
Per request, change
134
            if info is None or info not in allowed_info:
4797.85.31 by John Arbash Meinel
Categorize all of the requests as safe/unsafe/semi/stream for retrying purposes.
135
                unclassified_requests.append(key)
136
        if unclassified_requests:
137
            self.fail('These requests were not categorized as safe/unsafe'
7143.15.2 by Jelmer Vernooij
Run autopep8.
138
                      ' to retry: %s' % (unclassified_requests,))
4160.2.2 by Andrew Bennetts
Add setup_jail and teardown_jail to SmartServerRequest.
139
4144.3.1 by Andrew Bennetts
Add Repository.insert_stream_locked server-side implementation, plus tests for server-side _translate_error.
140
141
class TestSmartRequestHandlerErrorTranslation(TestCase):
142
    """Tests that SmartServerRequestHandler will translate exceptions raised by
143
    a SmartServerRequest into FailedSmartServerResponses.
144
    """
145
146
    def assertNoResponse(self, handler):
147
        self.assertEqual(None, handler.response)
148
149
    def assertResponseIsTranslatedError(self, handler):
6963.1.1 by Jelmer Vernooij
Fix a bunch of tests on python3.
150
        expected_translation = (b'NoSuchFile', b'xyzzy')
4144.3.1 by Andrew Bennetts
Add Repository.insert_stream_locked server-side implementation, plus tests for server-side _translate_error.
151
        self.assertEqual(
152
            request.FailedSmartServerResponse(expected_translation),
153
            handler.response)
154
155
    def test_error_translation_from_args_received(self):
156
        handler = request.SmartServerRequestHandler(
6963.1.2 by Jelmer Vernooij
Fix some more tests.
157
            None, {b'foo': DoErrorRequest}, '/')
6963.1.1 by Jelmer Vernooij
Fix a bunch of tests on python3.
158
        handler.args_received((b'foo',))
4144.3.1 by Andrew Bennetts
Add Repository.insert_stream_locked server-side implementation, plus tests for server-side _translate_error.
159
        self.assertResponseIsTranslatedError(handler)
160
161
    def test_error_translation_from_chunk_received(self):
162
        handler = request.SmartServerRequestHandler(
6963.1.2 by Jelmer Vernooij
Fix some more tests.
163
            None, {b'foo': ChunkErrorRequest}, '/')
6963.1.1 by Jelmer Vernooij
Fix a bunch of tests on python3.
164
        handler.args_received((b'foo',))
4144.3.1 by Andrew Bennetts
Add Repository.insert_stream_locked server-side implementation, plus tests for server-side _translate_error.
165
        self.assertNoResponse(handler)
6963.1.1 by Jelmer Vernooij
Fix a bunch of tests on python3.
166
        handler.accept_body(b'bytes')
4144.3.1 by Andrew Bennetts
Add Repository.insert_stream_locked server-side implementation, plus tests for server-side _translate_error.
167
        self.assertResponseIsTranslatedError(handler)
168
169
    def test_error_translation_from_end_received(self):
170
        handler = request.SmartServerRequestHandler(
6963.1.2 by Jelmer Vernooij
Fix some more tests.
171
            None, {b'foo': EndErrorRequest}, '/')
6963.1.1 by Jelmer Vernooij
Fix a bunch of tests on python3.
172
        handler.args_received((b'foo',))
4144.3.1 by Andrew Bennetts
Add Repository.insert_stream_locked server-side implementation, plus tests for server-side _translate_error.
173
        self.assertNoResponse(handler)
174
        handler.end_received()
175
        self.assertResponseIsTranslatedError(handler)
176
5677.2.8 by Martin
More tests for handling of unexpected remote errors
177
    def test_unexpected_error_translation(self):
178
        handler = request.SmartServerRequestHandler(
6963.1.2 by Jelmer Vernooij
Fix some more tests.
179
            None, {b'foo': DoUnexpectedErrorRequest}, '/')
6963.1.1 by Jelmer Vernooij
Fix a bunch of tests on python3.
180
        handler.args_received((b'foo',))
5677.2.8 by Martin
More tests for handling of unexpected remote errors
181
        self.assertEqual(
6963.1.1 by Jelmer Vernooij
Fix a bunch of tests on python3.
182
            request.FailedSmartServerResponse((b'error', b'KeyError', b"1")),
5677.2.8 by Martin
More tests for handling of unexpected remote errors
183
            handler.response)
184
4144.3.1 by Andrew Bennetts
Add Repository.insert_stream_locked server-side implementation, plus tests for server-side _translate_error.
185
186
class TestRequestHanderErrorTranslation(TestCase):
6670.4.16 by Jelmer Vernooij
Move smart to breezy.bzr.
187
    """Tests for breezy.bzr.smart.request._translate_error."""
4144.3.1 by Andrew Bennetts
Add Repository.insert_stream_locked server-side implementation, plus tests for server-side _translate_error.
188
189
    def assertTranslationEqual(self, expected_tuple, error):
190
        self.assertEqual(expected_tuple, request._translate_error(error))
191
192
    def test_NoSuchFile(self):
193
        self.assertTranslationEqual(
6963.1.1 by Jelmer Vernooij
Fix a bunch of tests on python3.
194
            (b'NoSuchFile', b'path'), errors.NoSuchFile('path'))
4144.3.1 by Andrew Bennetts
Add Repository.insert_stream_locked server-side implementation, plus tests for server-side _translate_error.
195
196
    def test_LockContention(self):
4556.2.7 by Andrew Bennetts
Update test.
197
        # For now, LockContentions are always transmitted with no details.
198
        # Eventually they should include a relpath or url or something else to
199
        # identify which lock is busy.
4144.3.1 by Andrew Bennetts
Add Repository.insert_stream_locked server-side implementation, plus tests for server-side _translate_error.
200
        self.assertTranslationEqual(
6963.1.1 by Jelmer Vernooij
Fix a bunch of tests on python3.
201
            (b'LockContention',), errors.LockContention('lock', 'msg'))
4144.3.1 by Andrew Bennetts
Add Repository.insert_stream_locked server-side implementation, plus tests for server-side _translate_error.
202
203
    def test_TokenMismatch(self):
204
        self.assertTranslationEqual(
6963.1.1 by Jelmer Vernooij
Fix a bunch of tests on python3.
205
            (b'TokenMismatch', b'some-token', b'actual-token'),
206
            errors.TokenMismatch(b'some-token', b'actual-token'))
4144.3.1 by Andrew Bennetts
Add Repository.insert_stream_locked server-side implementation, plus tests for server-side _translate_error.
207
5677.2.1 by Martin
Detect and report MemoryError during a smart server request
208
    def test_MemoryError(self):
6963.1.1 by Jelmer Vernooij
Fix a bunch of tests on python3.
209
        self.assertTranslationEqual((b"MemoryError",), MemoryError())
5677.2.1 by Martin
Detect and report MemoryError during a smart server request
210
6969.1.1 by Jelmer Vernooij
Handle GhostRevisionsHaveNoRevno in hpss.
211
    def test_GhostRevisionsHaveNoRevno(self):
212
        self.assertTranslationEqual(
213
            (b"GhostRevisionsHaveNoRevno", b'revid1', b'revid2'),
214
            errors.GhostRevisionsHaveNoRevno(b'revid1', b'revid2'))
215
5677.2.8 by Martin
More tests for handling of unexpected remote errors
216
    def test_generic_Exception(self):
6963.1.1 by Jelmer Vernooij
Fix a bunch of tests on python3.
217
        self.assertTranslationEqual((b'error', b'Exception', b""),
7143.15.2 by Jelmer Vernooij
Run autopep8.
218
                                    Exception())
5677.2.8 by Martin
More tests for handling of unexpected remote errors
219
220
    def test_generic_BzrError(self):
6963.1.1 by Jelmer Vernooij
Fix a bunch of tests on python3.
221
        self.assertTranslationEqual((b'error', b'BzrError', b"some text"),
7143.15.2 by Jelmer Vernooij
Run autopep8.
222
                                    errors.BzrError(msg="some text"))
5677.2.8 by Martin
More tests for handling of unexpected remote errors
223
224
    def test_generic_zlib_error(self):
225
        from zlib import error
226
        msg = "Error -3 while decompressing data: incorrect data check"
6963.1.1 by Jelmer Vernooij
Fix a bunch of tests on python3.
227
        self.assertTranslationEqual((b'error', b'zlib.error', msg.encode('utf-8')),
7143.15.2 by Jelmer Vernooij
Run autopep8.
228
                                    error(msg))
5677.2.8 by Martin
More tests for handling of unexpected remote errors
229
4160.2.2 by Andrew Bennetts
Add setup_jail and teardown_jail to SmartServerRequest.
230
231
class TestRequestJail(TestCaseWithMemoryTransport):
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
232
4160.2.2 by Andrew Bennetts
Add setup_jail and teardown_jail to SmartServerRequest.
233
    def test_jail(self):
234
        transport = self.get_transport('blah')
235
        req = request.SmartServerRequest(transport)
236
        self.assertEqual(None, request.jail_info.transports)
237
        req.setup_jail()
238
        self.assertEqual([transport], request.jail_info.transports)
239
        req.teardown_jail()
240
        self.assertEqual(None, request.jail_info.transports)
241
4160.2.5 by Andrew Bennetts
Add test_jail_hook.
242
243
class TestJailHook(TestCaseWithMemoryTransport):
244
4986.2.1 by Martin Pool
Remove tearDown in tests in favor of addCleanup
245
    def setUp(self):
4986.2.8 by Martin Pool
Add missing super.setUp call
246
        super(TestJailHook, self).setUp()
7143.15.2 by Jelmer Vernooij
Run autopep8.
247
4986.2.1 by Martin Pool
Remove tearDown in tests in favor of addCleanup
248
        def clear_jail_info():
249
            request.jail_info.transports = None
250
        self.addCleanup(clear_jail_info)
4160.2.5 by Andrew Bennetts
Add test_jail_hook.
251
252
    def test_jail_hook(self):
253
        request.jail_info.transports = None
254
        _pre_open_hook = request._pre_open_hook
255
        # Any transport is fine if jail_info.transports is None
256
        t = self.get_transport('foo')
257
        _pre_open_hook(t)
258
        # A transport in jail_info.transports is allowed
259
        request.jail_info.transports = [t]
260
        _pre_open_hook(t)
261
        # A child of a transport in jail_info is allowed
262
        _pre_open_hook(t.clone('child'))
263
        # A parent is not allowed
4294.2.10 by Robert Collins
Review feedback.
264
        self.assertRaises(errors.JailBreak, _pre_open_hook, t.clone('..'))
4160.2.5 by Andrew Bennetts
Add test_jail_hook.
265
        # A completely unrelated transport is not allowed
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
266
        self.assertRaises(errors.JailBreak, _pre_open_hook,
6083.1.1 by Jelmer Vernooij
Use get_transport_from_{url,path} in more places.
267
                          transport.get_transport_from_url('http://host/'))
4160.2.5 by Andrew Bennetts
Add test_jail_hook.
268
4205.2.1 by Andrew Bennetts
Fix BzrDir.open in non-main (and non-server-request) thread when bzrlib.smart.request's _pre_open_hook is installed.
269
    def test_open_bzrdir_in_non_main_thread(self):
270
        """Opening a bzrdir in a non-main thread should work ok.
7143.15.2 by Jelmer Vernooij
Run autopep8.
271
4205.2.1 by Andrew Bennetts
Fix BzrDir.open in non-main (and non-server-request) thread when bzrlib.smart.request's _pre_open_hook is installed.
272
        This makes sure that the globally-installed
6670.4.16 by Jelmer Vernooij
Move smart to breezy.bzr.
273
        breezy.bzr.smart.request._pre_open_hook, which uses a threading.local(),
4205.2.1 by Andrew Bennetts
Fix BzrDir.open in non-main (and non-server-request) thread when bzrlib.smart.request's _pre_open_hook is installed.
274
        works in a newly created thread.
275
        """
6653.6.5 by Jelmer Vernooij
Rename make_bzrdir to make_controldir.
276
        bzrdir = self.make_controldir('.')
4205.2.1 by Andrew Bennetts
Fix BzrDir.open in non-main (and non-server-request) thread when bzrlib.smart.request's _pre_open_hook is installed.
277
        transport = bzrdir.root_transport
278
        thread_result = []
7143.15.2 by Jelmer Vernooij
Run autopep8.
279
4205.2.1 by Andrew Bennetts
Fix BzrDir.open in non-main (and non-server-request) thread when bzrlib.smart.request's _pre_open_hook is installed.
280
        def t():
281
            BzrDir.open_from_transport(transport)
282
            thread_result.append('ok')
283
        thread = threading.Thread(target=t)
284
        thread.start()
285
        thread.join()
286
        self.assertEqual(['ok'], thread_result)