/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 breezy/tests/test_smart_request.py

  • Committer: Jelmer Vernooij
  • Date: 2020-04-05 19:11:34 UTC
  • mto: (7490.7.16 work)
  • mto: This revision was merged to the branch mainline in revision 7501.
  • Revision ID: jelmer@jelmer.uk-20200405191134-0aebh8ikiwygxma5
Populate the .gitignore file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2009 Canonical Ltd
 
1
# Copyright (C) 2009, 2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
 
"""Tests for smart server request infrastructure (bzrlib.smart.request)."""
 
17
"""Tests for smart server request infrastructure (breezy.bzr.smart.request)."""
18
18
 
19
19
import threading
20
20
 
21
 
from bzrlib import errors
22
 
from bzrlib.bzrdir import BzrDir
23
 
from bzrlib.smart import request
24
 
from bzrlib.tests import TestCase, TestCaseWithMemoryTransport
25
 
from bzrlib.transport import get_transport
 
21
from breezy import (
 
22
    errors,
 
23
    transport,
 
24
    )
 
25
from breezy.bzr.bzrdir import BzrDir
 
26
from breezy.bzr.smart import request
 
27
from breezy.tests import TestCase, TestCaseWithMemoryTransport
26
28
 
27
29
 
28
30
class NoBodyRequest(request.SmartServerRequest):
34
36
 
35
37
class DoErrorRequest(request.SmartServerRequest):
36
38
    """A request that raises an error from self.do()."""
37
 
    
 
39
 
38
40
    def do(self):
39
41
        raise errors.NoSuchFile('xyzzy')
40
42
 
41
43
 
 
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
 
42
51
class ChunkErrorRequest(request.SmartServerRequest):
43
52
    """A request that raises an error from self.do_chunk()."""
44
 
    
 
53
 
45
54
    def do(self):
46
55
        """No-op."""
47
56
        pass
52
61
 
53
62
class EndErrorRequest(request.SmartServerRequest):
54
63
    """A request that raises an error from self.do_end()."""
55
 
    
 
64
 
56
65
    def do(self):
57
66
        """No-op."""
58
67
        pass
60
69
    def do_chunk(self, bytes):
61
70
        """No-op."""
62
71
        pass
63
 
        
 
72
 
64
73
    def do_end(self):
65
74
        raise errors.NoSuchFile('xyzzy')
66
75
 
81
90
        self.jail_transports_log.append(request.jail_info.transports)
82
91
 
83
92
 
 
93
class TestErrors(TestCase):
 
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
 
84
101
class TestSmartRequest(TestCase):
85
102
 
86
103
    def test_request_class_without_do_body(self):
90
107
        # Create a SmartServerRequestHandler with a SmartServerRequest subclass
91
108
        # that does not implement do_body.
92
109
        handler = request.SmartServerRequestHandler(
93
 
            None, {'foo': NoBodyRequest}, '/')
 
110
            None, {b'foo': NoBodyRequest}, '/')
94
111
        # Emulate a request with no body (i.e. just args).
95
 
        handler.args_received(('foo',))
 
112
        handler.args_received((b'foo',))
96
113
        handler.end_received()
97
114
        # Request done, no exception was raised.
98
115
 
99
116
    def test_only_request_code_is_jailed(self):
100
117
        transport = 'dummy transport'
101
118
        handler = request.SmartServerRequestHandler(
102
 
            transport, {'foo': CheckJailRequest}, '/')
103
 
        handler.args_received(('foo',))
 
119
            transport, {b'foo': CheckJailRequest}, '/')
 
120
        handler.args_received((b'foo',))
104
121
        self.assertEqual(None, request.jail_info.transports)
105
 
        handler.accept_body('bytes')
 
122
        handler.accept_body(b'bytes')
106
123
        self.assertEqual(None, request.jail_info.transports)
107
124
        handler.end_received()
108
125
        self.assertEqual(None, request.jail_info.transports)
109
126
        self.assertEqual(
110
127
            [[transport]] * 3, handler._command.jail_transports_log)
111
128
 
 
129
    def test_all_registered_requests_are_safety_qualified(self):
 
130
        unclassified_requests = []
 
131
        allowed_info = ('read', 'idem', 'mutate', 'semivfs', 'semi', 'stream')
 
132
        for key in request.request_handlers.keys():
 
133
            info = request.request_handlers.get_info(key)
 
134
            if info is None or info not in allowed_info:
 
135
                unclassified_requests.append(key)
 
136
        if unclassified_requests:
 
137
            self.fail('These requests were not categorized as safe/unsafe'
 
138
                      ' to retry: %s' % (unclassified_requests,))
112
139
 
113
140
 
114
141
class TestSmartRequestHandlerErrorTranslation(TestCase):
120
147
        self.assertEqual(None, handler.response)
121
148
 
122
149
    def assertResponseIsTranslatedError(self, handler):
123
 
        expected_translation = ('NoSuchFile', 'xyzzy')
 
150
        expected_translation = (b'NoSuchFile', b'xyzzy')
124
151
        self.assertEqual(
125
152
            request.FailedSmartServerResponse(expected_translation),
126
153
            handler.response)
127
154
 
128
155
    def test_error_translation_from_args_received(self):
129
156
        handler = request.SmartServerRequestHandler(
130
 
            None, {'foo': DoErrorRequest}, '/')
131
 
        handler.args_received(('foo',))
 
157
            None, {b'foo': DoErrorRequest}, '/')
 
158
        handler.args_received((b'foo',))
132
159
        self.assertResponseIsTranslatedError(handler)
133
160
 
134
161
    def test_error_translation_from_chunk_received(self):
135
162
        handler = request.SmartServerRequestHandler(
136
 
            None, {'foo': ChunkErrorRequest}, '/')
137
 
        handler.args_received(('foo',))
 
163
            None, {b'foo': ChunkErrorRequest}, '/')
 
164
        handler.args_received((b'foo',))
138
165
        self.assertNoResponse(handler)
139
 
        handler.accept_body('bytes')
 
166
        handler.accept_body(b'bytes')
140
167
        self.assertResponseIsTranslatedError(handler)
141
168
 
142
169
    def test_error_translation_from_end_received(self):
143
170
        handler = request.SmartServerRequestHandler(
144
 
            None, {'foo': EndErrorRequest}, '/')
145
 
        handler.args_received(('foo',))
 
171
            None, {b'foo': EndErrorRequest}, '/')
 
172
        handler.args_received((b'foo',))
146
173
        self.assertNoResponse(handler)
147
174
        handler.end_received()
148
175
        self.assertResponseIsTranslatedError(handler)
149
176
 
 
177
    def test_unexpected_error_translation(self):
 
178
        handler = request.SmartServerRequestHandler(
 
179
            None, {b'foo': DoUnexpectedErrorRequest}, '/')
 
180
        handler.args_received((b'foo',))
 
181
        self.assertEqual(
 
182
            request.FailedSmartServerResponse((b'error', b'KeyError', b"1")),
 
183
            handler.response)
 
184
 
150
185
 
151
186
class TestRequestHanderErrorTranslation(TestCase):
152
 
    """Tests for bzrlib.smart.request._translate_error."""
 
187
    """Tests for breezy.bzr.smart.request._translate_error."""
153
188
 
154
189
    def assertTranslationEqual(self, expected_tuple, error):
155
190
        self.assertEqual(expected_tuple, request._translate_error(error))
156
191
 
157
192
    def test_NoSuchFile(self):
158
193
        self.assertTranslationEqual(
159
 
            ('NoSuchFile', 'path'), errors.NoSuchFile('path'))
 
194
            (b'NoSuchFile', b'path'), errors.NoSuchFile('path'))
160
195
 
161
196
    def test_LockContention(self):
162
197
        # For now, LockContentions are always transmitted with no details.
163
198
        # Eventually they should include a relpath or url or something else to
164
199
        # identify which lock is busy.
165
200
        self.assertTranslationEqual(
166
 
            ('LockContention',), errors.LockContention('lock', 'msg'))
 
201
            (b'LockContention',), errors.LockContention('lock', 'msg'))
167
202
 
168
203
    def test_TokenMismatch(self):
169
204
        self.assertTranslationEqual(
170
 
            ('TokenMismatch', 'some-token', 'actual-token'),
171
 
            errors.TokenMismatch('some-token', 'actual-token'))
 
205
            (b'TokenMismatch', b'some-token', b'actual-token'),
 
206
            errors.TokenMismatch(b'some-token', b'actual-token'))
 
207
 
 
208
    def test_MemoryError(self):
 
209
        self.assertTranslationEqual((b"MemoryError",), MemoryError())
 
210
 
 
211
    def test_GhostRevisionsHaveNoRevno(self):
 
212
        self.assertTranslationEqual(
 
213
            (b"GhostRevisionsHaveNoRevno", b'revid1', b'revid2'),
 
214
            errors.GhostRevisionsHaveNoRevno(b'revid1', b'revid2'))
 
215
 
 
216
    def test_generic_Exception(self):
 
217
        self.assertTranslationEqual((b'error', b'Exception', b""),
 
218
                                    Exception())
 
219
 
 
220
    def test_generic_BzrError(self):
 
221
        self.assertTranslationEqual((b'error', b'BzrError', b"some text"),
 
222
                                    errors.BzrError(msg="some text"))
 
223
 
 
224
    def test_generic_zlib_error(self):
 
225
        from zlib import error
 
226
        msg = "Error -3 while decompressing data: incorrect data check"
 
227
        self.assertTranslationEqual((b'error', b'zlib.error', msg.encode('utf-8')),
 
228
                                    error(msg))
172
229
 
173
230
 
174
231
class TestRequestJail(TestCaseWithMemoryTransport):
175
 
    
 
232
 
176
233
    def test_jail(self):
177
234
        transport = self.get_transport('blah')
178
235
        req = request.SmartServerRequest(transport)
185
242
 
186
243
class TestJailHook(TestCaseWithMemoryTransport):
187
244
 
188
 
    def tearDown(self):
189
 
        request.jail_info.transports = None
190
 
        TestCaseWithMemoryTransport.tearDown(self)
 
245
    def setUp(self):
 
246
        super(TestJailHook, self).setUp()
 
247
 
 
248
        def clear_jail_info():
 
249
            request.jail_info.transports = None
 
250
        self.addCleanup(clear_jail_info)
191
251
 
192
252
    def test_jail_hook(self):
193
253
        request.jail_info.transports = None
203
263
        # A parent is not allowed
204
264
        self.assertRaises(errors.JailBreak, _pre_open_hook, t.clone('..'))
205
265
        # A completely unrelated transport is not allowed
206
 
        self.assertRaises(
207
 
            errors.JailBreak, _pre_open_hook, get_transport('http://host/'))
 
266
        self.assertRaises(errors.JailBreak, _pre_open_hook,
 
267
                          transport.get_transport_from_url('http://host/'))
208
268
 
209
269
    def test_open_bzrdir_in_non_main_thread(self):
210
270
        """Opening a bzrdir in a non-main thread should work ok.
211
 
        
 
271
 
212
272
        This makes sure that the globally-installed
213
 
        bzrlib.smart.request._pre_open_hook, which uses a threading.local(),
 
273
        breezy.bzr.smart.request._pre_open_hook, which uses a threading.local(),
214
274
        works in a newly created thread.
215
275
        """
216
 
        bzrdir = self.make_bzrdir('.')
 
276
        bzrdir = self.make_controldir('.')
217
277
        transport = bzrdir.root_transport
218
278
        thread_result = []
 
279
 
219
280
        def t():
220
281
            BzrDir.open_from_transport(transport)
221
282
            thread_result.append('ok')
223
284
        thread.start()
224
285
        thread.join()
225
286
        self.assertEqual(['ok'], thread_result)
226