107
92
# Create a SmartServerRequestHandler with a SmartServerRequest subclass
108
93
# that does not implement do_body.
109
94
handler = request.SmartServerRequestHandler(
110
None, {b'foo': NoBodyRequest}, '/')
95
None, {'foo': NoBodyRequest}, '/')
111
96
# Emulate a request with no body (i.e. just args).
112
handler.args_received((b'foo',))
97
handler.args_received(('foo',))
113
98
handler.end_received()
114
99
# Request done, no exception was raised.
116
101
def test_only_request_code_is_jailed(self):
117
102
transport = 'dummy transport'
118
103
handler = request.SmartServerRequestHandler(
119
transport, {b'foo': CheckJailRequest}, '/')
120
handler.args_received((b'foo',))
104
transport, {'foo': CheckJailRequest}, '/')
105
handler.args_received(('foo',))
121
106
self.assertEqual(None, request.jail_info.transports)
122
handler.accept_body(b'bytes')
107
handler.accept_body('bytes')
123
108
self.assertEqual(None, request.jail_info.transports)
124
109
handler.end_received()
125
110
self.assertEqual(None, request.jail_info.transports)
126
111
self.assertEqual(
127
112
[[transport]] * 3, handler._command.jail_transports_log)
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,))
141
116
class TestSmartRequestHandlerErrorTranslation(TestCase):
147
122
self.assertEqual(None, handler.response)
149
124
def assertResponseIsTranslatedError(self, handler):
150
expected_translation = (b'NoSuchFile', b'xyzzy')
125
expected_translation = ('NoSuchFile', 'xyzzy')
151
126
self.assertEqual(
152
127
request.FailedSmartServerResponse(expected_translation),
153
128
handler.response)
155
130
def test_error_translation_from_args_received(self):
156
131
handler = request.SmartServerRequestHandler(
157
None, {b'foo': DoErrorRequest}, '/')
158
handler.args_received((b'foo',))
132
None, {'foo': DoErrorRequest}, '/')
133
handler.args_received(('foo',))
159
134
self.assertResponseIsTranslatedError(handler)
161
136
def test_error_translation_from_chunk_received(self):
162
137
handler = request.SmartServerRequestHandler(
163
None, {b'foo': ChunkErrorRequest}, '/')
164
handler.args_received((b'foo',))
138
None, {'foo': ChunkErrorRequest}, '/')
139
handler.args_received(('foo',))
165
140
self.assertNoResponse(handler)
166
handler.accept_body(b'bytes')
141
handler.accept_body('bytes')
167
142
self.assertResponseIsTranslatedError(handler)
169
144
def test_error_translation_from_end_received(self):
170
145
handler = request.SmartServerRequestHandler(
171
None, {b'foo': EndErrorRequest}, '/')
172
handler.args_received((b'foo',))
146
None, {'foo': EndErrorRequest}, '/')
147
handler.args_received(('foo',))
173
148
self.assertNoResponse(handler)
174
149
handler.end_received()
175
150
self.assertResponseIsTranslatedError(handler)
177
def test_unexpected_error_translation(self):
178
handler = request.SmartServerRequestHandler(
179
None, {b'foo': DoUnexpectedErrorRequest}, '/')
180
handler.args_received((b'foo',))
182
request.FailedSmartServerResponse((b'error', b'KeyError', b"1")),
186
153
class TestRequestHanderErrorTranslation(TestCase):
187
"""Tests for breezy.bzr.smart.request._translate_error."""
154
"""Tests for bzrlib.smart.request._translate_error."""
189
156
def assertTranslationEqual(self, expected_tuple, error):
190
157
self.assertEqual(expected_tuple, request._translate_error(error))
192
159
def test_NoSuchFile(self):
193
160
self.assertTranslationEqual(
194
(b'NoSuchFile', b'path'), errors.NoSuchFile('path'))
161
('NoSuchFile', 'path'), errors.NoSuchFile('path'))
196
163
def test_LockContention(self):
197
164
# For now, LockContentions are always transmitted with no details.
198
165
# Eventually they should include a relpath or url or something else to
199
166
# identify which lock is busy.
200
167
self.assertTranslationEqual(
201
(b'LockContention',), errors.LockContention('lock', 'msg'))
168
('LockContention',), errors.LockContention('lock', 'msg'))
203
170
def test_TokenMismatch(self):
204
171
self.assertTranslationEqual(
205
(b'TokenMismatch', b'some-token', b'actual-token'),
206
errors.TokenMismatch(b'some-token', b'actual-token'))
208
def test_MemoryError(self):
209
self.assertTranslationEqual((b"MemoryError",), MemoryError())
211
def test_GhostRevisionsHaveNoRevno(self):
212
self.assertTranslationEqual(
213
(b"GhostRevisionsHaveNoRevno", b'revid1', b'revid2'),
214
errors.GhostRevisionsHaveNoRevno(b'revid1', b'revid2'))
216
def test_generic_Exception(self):
217
self.assertTranslationEqual((b'error', b'Exception', b""),
220
def test_generic_BzrError(self):
221
self.assertTranslationEqual((b'error', b'BzrError', b"some text"),
222
errors.BzrError(msg="some text"))
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')),
172
('TokenMismatch', 'some-token', 'actual-token'),
173
errors.TokenMismatch('some-token', 'actual-token'))
231
176
class TestRequestJail(TestCaseWithMemoryTransport):
264
206
self.assertRaises(errors.JailBreak, _pre_open_hook, t.clone('..'))
265
207
# A completely unrelated transport is not allowed
266
208
self.assertRaises(errors.JailBreak, _pre_open_hook,
267
transport.get_transport_from_url('http://host/'))
209
transport.get_transport('http://host/'))
269
211
def test_open_bzrdir_in_non_main_thread(self):
270
212
"""Opening a bzrdir in a non-main thread should work ok.
272
214
This makes sure that the globally-installed
273
breezy.bzr.smart.request._pre_open_hook, which uses a threading.local(),
215
bzrlib.smart.request._pre_open_hook, which uses a threading.local(),
274
216
works in a newly created thread.
276
bzrdir = self.make_controldir('.')
218
bzrdir = self.make_bzrdir('.')
277
219
transport = bzrdir.root_transport
278
220
thread_result = []
281
222
BzrDir.open_from_transport(transport)
282
223
thread_result.append('ok')