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

  • Committer: Robert Collins
  • Date: 2010-05-05 00:05:29 UTC
  • mto: This revision was merged to the branch mainline in revision 5206.
  • Revision ID: robertc@robertcollins.net-20100505000529-ltmllyms5watqj5u
Make 'pydoc bzrlib.tests.build_tree_shape' useful.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2009, 2010 Canonical Ltd
 
1
# Copyright (C) 2009 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 (breezy.bzr.smart.request)."""
 
17
"""Tests for smart server request infrastructure (bzrlib.smart.request)."""
18
18
 
19
19
import threading
20
20
 
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
 
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
28
26
 
29
27
 
30
28
class NoBodyRequest(request.SmartServerRequest):
36
34
 
37
35
class DoErrorRequest(request.SmartServerRequest):
38
36
    """A request that raises an error from self.do()."""
39
 
 
 
37
    
40
38
    def do(self):
41
39
        raise errors.NoSuchFile('xyzzy')
42
40
 
43
41
 
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
 
 
51
42
class ChunkErrorRequest(request.SmartServerRequest):
52
43
    """A request that raises an error from self.do_chunk()."""
53
 
 
 
44
    
54
45
    def do(self):
55
46
        """No-op."""
56
47
        pass
61
52
 
62
53
class EndErrorRequest(request.SmartServerRequest):
63
54
    """A request that raises an error from self.do_end()."""
64
 
 
 
55
    
65
56
    def do(self):
66
57
        """No-op."""
67
58
        pass
69
60
    def do_chunk(self, bytes):
70
61
        """No-op."""
71
62
        pass
72
 
 
 
63
        
73
64
    def do_end(self):
74
65
        raise errors.NoSuchFile('xyzzy')
75
66
 
90
81
        self.jail_transports_log.append(request.jail_info.transports)
91
82
 
92
83
 
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
 
 
101
84
class TestSmartRequest(TestCase):
102
85
 
103
86
    def test_request_class_without_do_body(self):
107
90
        # Create a SmartServerRequestHandler with a SmartServerRequest subclass
108
91
        # that does not implement do_body.
109
92
        handler = request.SmartServerRequestHandler(
110
 
            None, {b'foo': NoBodyRequest}, '/')
 
93
            None, {'foo': NoBodyRequest}, '/')
111
94
        # Emulate a request with no body (i.e. just args).
112
 
        handler.args_received((b'foo',))
 
95
        handler.args_received(('foo',))
113
96
        handler.end_received()
114
97
        # Request done, no exception was raised.
115
98
 
116
99
    def test_only_request_code_is_jailed(self):
117
100
        transport = 'dummy transport'
118
101
        handler = request.SmartServerRequestHandler(
119
 
            transport, {b'foo': CheckJailRequest}, '/')
120
 
        handler.args_received((b'foo',))
 
102
            transport, {'foo': CheckJailRequest}, '/')
 
103
        handler.args_received(('foo',))
121
104
        self.assertEqual(None, request.jail_info.transports)
122
 
        handler.accept_body(b'bytes')
 
105
        handler.accept_body('bytes')
123
106
        self.assertEqual(None, request.jail_info.transports)
124
107
        handler.end_received()
125
108
        self.assertEqual(None, request.jail_info.transports)
126
109
        self.assertEqual(
127
110
            [[transport]] * 3, handler._command.jail_transports_log)
128
111
 
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,))
139
112
 
140
113
 
141
114
class TestSmartRequestHandlerErrorTranslation(TestCase):
147
120
        self.assertEqual(None, handler.response)
148
121
 
149
122
    def assertResponseIsTranslatedError(self, handler):
150
 
        expected_translation = (b'NoSuchFile', b'xyzzy')
 
123
        expected_translation = ('NoSuchFile', 'xyzzy')
151
124
        self.assertEqual(
152
125
            request.FailedSmartServerResponse(expected_translation),
153
126
            handler.response)
154
127
 
155
128
    def test_error_translation_from_args_received(self):
156
129
        handler = request.SmartServerRequestHandler(
157
 
            None, {b'foo': DoErrorRequest}, '/')
158
 
        handler.args_received((b'foo',))
 
130
            None, {'foo': DoErrorRequest}, '/')
 
131
        handler.args_received(('foo',))
159
132
        self.assertResponseIsTranslatedError(handler)
160
133
 
161
134
    def test_error_translation_from_chunk_received(self):
162
135
        handler = request.SmartServerRequestHandler(
163
 
            None, {b'foo': ChunkErrorRequest}, '/')
164
 
        handler.args_received((b'foo',))
 
136
            None, {'foo': ChunkErrorRequest}, '/')
 
137
        handler.args_received(('foo',))
165
138
        self.assertNoResponse(handler)
166
 
        handler.accept_body(b'bytes')
 
139
        handler.accept_body('bytes')
167
140
        self.assertResponseIsTranslatedError(handler)
168
141
 
169
142
    def test_error_translation_from_end_received(self):
170
143
        handler = request.SmartServerRequestHandler(
171
 
            None, {b'foo': EndErrorRequest}, '/')
172
 
        handler.args_received((b'foo',))
 
144
            None, {'foo': EndErrorRequest}, '/')
 
145
        handler.args_received(('foo',))
173
146
        self.assertNoResponse(handler)
174
147
        handler.end_received()
175
148
        self.assertResponseIsTranslatedError(handler)
176
149
 
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
 
 
185
150
 
186
151
class TestRequestHanderErrorTranslation(TestCase):
187
 
    """Tests for breezy.bzr.smart.request._translate_error."""
 
152
    """Tests for bzrlib.smart.request._translate_error."""
188
153
 
189
154
    def assertTranslationEqual(self, expected_tuple, error):
190
155
        self.assertEqual(expected_tuple, request._translate_error(error))
191
156
 
192
157
    def test_NoSuchFile(self):
193
158
        self.assertTranslationEqual(
194
 
            (b'NoSuchFile', b'path'), errors.NoSuchFile('path'))
 
159
            ('NoSuchFile', 'path'), errors.NoSuchFile('path'))
195
160
 
196
161
    def test_LockContention(self):
197
162
        # For now, LockContentions are always transmitted with no details.
198
163
        # Eventually they should include a relpath or url or something else to
199
164
        # identify which lock is busy.
200
165
        self.assertTranslationEqual(
201
 
            (b'LockContention',), errors.LockContention('lock', 'msg'))
 
166
            ('LockContention',), errors.LockContention('lock', 'msg'))
202
167
 
203
168
    def test_TokenMismatch(self):
204
169
        self.assertTranslationEqual(
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))
 
170
            ('TokenMismatch', 'some-token', 'actual-token'),
 
171
            errors.TokenMismatch('some-token', 'actual-token'))
229
172
 
230
173
 
231
174
class TestRequestJail(TestCaseWithMemoryTransport):
232
 
 
 
175
    
233
176
    def test_jail(self):
234
177
        transport = self.get_transport('blah')
235
178
        req = request.SmartServerRequest(transport)
242
185
 
243
186
class TestJailHook(TestCaseWithMemoryTransport):
244
187
 
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)
 
188
    def tearDown(self):
 
189
        request.jail_info.transports = None
 
190
        TestCaseWithMemoryTransport.tearDown(self)
251
191
 
252
192
    def test_jail_hook(self):
253
193
        request.jail_info.transports = None
263
203
        # A parent is not allowed
264
204
        self.assertRaises(errors.JailBreak, _pre_open_hook, t.clone('..'))
265
205
        # A completely unrelated transport is not allowed
266
 
        self.assertRaises(errors.JailBreak, _pre_open_hook,
267
 
                          transport.get_transport_from_url('http://host/'))
 
206
        self.assertRaises(
 
207
            errors.JailBreak, _pre_open_hook, get_transport('http://host/'))
268
208
 
269
209
    def test_open_bzrdir_in_non_main_thread(self):
270
210
        """Opening a bzrdir in a non-main thread should work ok.
271
 
 
 
211
        
272
212
        This makes sure that the globally-installed
273
 
        breezy.bzr.smart.request._pre_open_hook, which uses a threading.local(),
 
213
        bzrlib.smart.request._pre_open_hook, which uses a threading.local(),
274
214
        works in a newly created thread.
275
215
        """
276
 
        bzrdir = self.make_controldir('.')
 
216
        bzrdir = self.make_bzrdir('.')
277
217
        transport = bzrdir.root_transport
278
218
        thread_result = []
279
 
 
280
219
        def t():
281
220
            BzrDir.open_from_transport(transport)
282
221
            thread_result.append('ok')
284
223
        thread.start()
285
224
        thread.join()
286
225
        self.assertEqual(['ok'], thread_result)
 
226