##// END OF EJS Templates
tests: skip wireproto clientreactor tests on Python 3.6.0-3.6.3 inclusive...
Augie Fackler -
r40516:07b87ee2 default
parent child Browse files
Show More
@@ -1,604 +1,610 b''
1 from __future__ import absolute_import
1 from __future__ import absolute_import
2
2
3 import sys
3 import unittest
4 import unittest
4 import zlib
5 import zlib
5
6
6 from mercurial import (
7 from mercurial import (
7 error,
8 error,
8 ui as uimod,
9 ui as uimod,
9 wireprotoframing as framing,
10 wireprotoframing as framing,
10 )
11 )
11 from mercurial.utils import (
12 from mercurial.utils import (
12 cborutil,
13 cborutil,
13 )
14 )
14
15
15 try:
16 try:
16 from mercurial import zstd
17 from mercurial import zstd
17 zstd.__version__
18 zstd.__version__
18 except ImportError:
19 except ImportError:
19 zstd = None
20 zstd = None
20
21
21 ffs = framing.makeframefromhumanstring
22 ffs = framing.makeframefromhumanstring
22
23
23 globalui = uimod.ui()
24 globalui = uimod.ui()
24
25
25 def sendframe(reactor, frame):
26 def sendframe(reactor, frame):
26 """Send a frame bytearray to a reactor."""
27 """Send a frame bytearray to a reactor."""
27 header = framing.parseheader(frame)
28 header = framing.parseheader(frame)
28 payload = frame[framing.FRAME_HEADER_SIZE:]
29 payload = frame[framing.FRAME_HEADER_SIZE:]
29 assert len(payload) == header.length
30 assert len(payload) == header.length
30
31
31 return reactor.onframerecv(framing.frame(header.requestid,
32 return reactor.onframerecv(framing.frame(header.requestid,
32 header.streamid,
33 header.streamid,
33 header.streamflags,
34 header.streamflags,
34 header.typeid,
35 header.typeid,
35 header.flags,
36 header.flags,
36 payload))
37 payload))
37
38
38 class SingleSendTests(unittest.TestCase):
39 class SingleSendTests(unittest.TestCase):
39 """A reactor that can only send once rejects subsequent sends."""
40 """A reactor that can only send once rejects subsequent sends."""
40
41
41 if not getattr(unittest.TestCase, 'assertRaisesRegex', False):
42 if not getattr(unittest.TestCase, 'assertRaisesRegex', False):
42 # Python 3.7 deprecates the regex*p* version, but 2.7 lacks
43 # Python 3.7 deprecates the regex*p* version, but 2.7 lacks
43 # the regex version.
44 # the regex version.
44 assertRaisesRegex = (# camelcase-required
45 assertRaisesRegex = (# camelcase-required
45 unittest.TestCase.assertRaisesRegexp)
46 unittest.TestCase.assertRaisesRegexp)
46
47
47 def testbasic(self):
48 def testbasic(self):
48 reactor = framing.clientreactor(globalui,
49 reactor = framing.clientreactor(globalui,
49 hasmultiplesend=False,
50 hasmultiplesend=False,
50 buffersends=True)
51 buffersends=True)
51
52
52 request, action, meta = reactor.callcommand(b'foo', {})
53 request, action, meta = reactor.callcommand(b'foo', {})
53 self.assertEqual(request.state, b'pending')
54 self.assertEqual(request.state, b'pending')
54 self.assertEqual(action, b'noop')
55 self.assertEqual(action, b'noop')
55
56
56 action, meta = reactor.flushcommands()
57 action, meta = reactor.flushcommands()
57 self.assertEqual(action, b'sendframes')
58 self.assertEqual(action, b'sendframes')
58
59
59 for frame in meta[b'framegen']:
60 for frame in meta[b'framegen']:
60 self.assertEqual(request.state, b'sending')
61 self.assertEqual(request.state, b'sending')
61
62
62 self.assertEqual(request.state, b'sent')
63 self.assertEqual(request.state, b'sent')
63
64
64 with self.assertRaisesRegex(error.ProgrammingError,
65 with self.assertRaisesRegex(error.ProgrammingError,
65 'cannot issue new commands'):
66 'cannot issue new commands'):
66 reactor.callcommand(b'foo', {})
67 reactor.callcommand(b'foo', {})
67
68
68 with self.assertRaisesRegex(error.ProgrammingError,
69 with self.assertRaisesRegex(error.ProgrammingError,
69 'cannot issue new commands'):
70 'cannot issue new commands'):
70 reactor.callcommand(b'foo', {})
71 reactor.callcommand(b'foo', {})
71
72
72 class NoBufferTests(unittest.TestCase):
73 class NoBufferTests(unittest.TestCase):
73 """A reactor without send buffering sends requests immediately."""
74 """A reactor without send buffering sends requests immediately."""
74 def testbasic(self):
75 def testbasic(self):
75 reactor = framing.clientreactor(globalui,
76 reactor = framing.clientreactor(globalui,
76 hasmultiplesend=True,
77 hasmultiplesend=True,
77 buffersends=False)
78 buffersends=False)
78
79
79 request, action, meta = reactor.callcommand(b'command1', {})
80 request, action, meta = reactor.callcommand(b'command1', {})
80 self.assertEqual(request.requestid, 1)
81 self.assertEqual(request.requestid, 1)
81 self.assertEqual(action, b'sendframes')
82 self.assertEqual(action, b'sendframes')
82
83
83 self.assertEqual(request.state, b'pending')
84 self.assertEqual(request.state, b'pending')
84
85
85 for frame in meta[b'framegen']:
86 for frame in meta[b'framegen']:
86 self.assertEqual(request.state, b'sending')
87 self.assertEqual(request.state, b'sending')
87
88
88 self.assertEqual(request.state, b'sent')
89 self.assertEqual(request.state, b'sent')
89
90
90 action, meta = reactor.flushcommands()
91 action, meta = reactor.flushcommands()
91 self.assertEqual(action, b'noop')
92 self.assertEqual(action, b'noop')
92
93
93 # And we can send another command.
94 # And we can send another command.
94 request, action, meta = reactor.callcommand(b'command2', {})
95 request, action, meta = reactor.callcommand(b'command2', {})
95 self.assertEqual(request.requestid, 3)
96 self.assertEqual(request.requestid, 3)
96 self.assertEqual(action, b'sendframes')
97 self.assertEqual(action, b'sendframes')
97
98
98 for frame in meta[b'framegen']:
99 for frame in meta[b'framegen']:
99 self.assertEqual(request.state, b'sending')
100 self.assertEqual(request.state, b'sending')
100
101
101 self.assertEqual(request.state, b'sent')
102 self.assertEqual(request.state, b'sent')
102
103
103 class BadFrameRecvTests(unittest.TestCase):
104 class BadFrameRecvTests(unittest.TestCase):
104 if not getattr(unittest.TestCase, 'assertRaisesRegex', False):
105 if not getattr(unittest.TestCase, 'assertRaisesRegex', False):
105 # Python 3.7 deprecates the regex*p* version, but 2.7 lacks
106 # Python 3.7 deprecates the regex*p* version, but 2.7 lacks
106 # the regex version.
107 # the regex version.
107 assertRaisesRegex = (# camelcase-required
108 assertRaisesRegex = (# camelcase-required
108 unittest.TestCase.assertRaisesRegexp)
109 unittest.TestCase.assertRaisesRegexp)
109
110
110 def testoddstream(self):
111 def testoddstream(self):
111 reactor = framing.clientreactor(globalui)
112 reactor = framing.clientreactor(globalui)
112
113
113 action, meta = sendframe(reactor, ffs(b'1 1 0 1 0 foo'))
114 action, meta = sendframe(reactor, ffs(b'1 1 0 1 0 foo'))
114 self.assertEqual(action, b'error')
115 self.assertEqual(action, b'error')
115 self.assertEqual(meta[b'message'],
116 self.assertEqual(meta[b'message'],
116 b'received frame with odd numbered stream ID: 1')
117 b'received frame with odd numbered stream ID: 1')
117
118
118 def testunknownstream(self):
119 def testunknownstream(self):
119 reactor = framing.clientreactor(globalui)
120 reactor = framing.clientreactor(globalui)
120
121
121 action, meta = sendframe(reactor, ffs(b'1 0 0 1 0 foo'))
122 action, meta = sendframe(reactor, ffs(b'1 0 0 1 0 foo'))
122 self.assertEqual(action, b'error')
123 self.assertEqual(action, b'error')
123 self.assertEqual(meta[b'message'],
124 self.assertEqual(meta[b'message'],
124 b'received frame on unknown stream without beginning '
125 b'received frame on unknown stream without beginning '
125 b'of stream flag set')
126 b'of stream flag set')
126
127
127 def testunhandledframetype(self):
128 def testunhandledframetype(self):
128 reactor = framing.clientreactor(globalui, buffersends=False)
129 reactor = framing.clientreactor(globalui, buffersends=False)
129
130
130 request, action, meta = reactor.callcommand(b'foo', {})
131 request, action, meta = reactor.callcommand(b'foo', {})
131 for frame in meta[b'framegen']:
132 for frame in meta[b'framegen']:
132 pass
133 pass
133
134
134 with self.assertRaisesRegex(error.ProgrammingError,
135 with self.assertRaisesRegex(error.ProgrammingError,
135 'unhandled frame type'):
136 'unhandled frame type'):
136 sendframe(reactor, ffs(b'1 0 stream-begin text-output 0 foo'))
137 sendframe(reactor, ffs(b'1 0 stream-begin text-output 0 foo'))
137
138
138 class StreamTests(unittest.TestCase):
139 class StreamTests(unittest.TestCase):
139 def testmultipleresponseframes(self):
140 def testmultipleresponseframes(self):
140 reactor = framing.clientreactor(globalui, buffersends=False)
141 reactor = framing.clientreactor(globalui, buffersends=False)
141
142
142 request, action, meta = reactor.callcommand(b'foo', {})
143 request, action, meta = reactor.callcommand(b'foo', {})
143
144
144 self.assertEqual(action, b'sendframes')
145 self.assertEqual(action, b'sendframes')
145 for f in meta[b'framegen']:
146 for f in meta[b'framegen']:
146 pass
147 pass
147
148
148 action, meta = sendframe(
149 action, meta = sendframe(
149 reactor,
150 reactor,
150 ffs(b'%d 0 stream-begin command-response 0 foo' %
151 ffs(b'%d 0 stream-begin command-response 0 foo' %
151 request.requestid))
152 request.requestid))
152 self.assertEqual(action, b'responsedata')
153 self.assertEqual(action, b'responsedata')
153
154
154 action, meta = sendframe(
155 action, meta = sendframe(
155 reactor,
156 reactor,
156 ffs(b'%d 0 0 command-response eos bar' % request.requestid))
157 ffs(b'%d 0 0 command-response eos bar' % request.requestid))
157 self.assertEqual(action, b'responsedata')
158 self.assertEqual(action, b'responsedata')
158
159
159 class RedirectTests(unittest.TestCase):
160 class RedirectTests(unittest.TestCase):
160 def testredirect(self):
161 def testredirect(self):
161 reactor = framing.clientreactor(globalui, buffersends=False)
162 reactor = framing.clientreactor(globalui, buffersends=False)
162
163
163 redirect = {
164 redirect = {
164 b'targets': [b'a', b'b'],
165 b'targets': [b'a', b'b'],
165 b'hashes': [b'sha256'],
166 b'hashes': [b'sha256'],
166 }
167 }
167
168
168 request, action, meta = reactor.callcommand(
169 request, action, meta = reactor.callcommand(
169 b'foo', {}, redirect=redirect)
170 b'foo', {}, redirect=redirect)
170
171
171 self.assertEqual(action, b'sendframes')
172 self.assertEqual(action, b'sendframes')
172
173
173 frames = list(meta[b'framegen'])
174 frames = list(meta[b'framegen'])
174 self.assertEqual(len(frames), 1)
175 self.assertEqual(len(frames), 1)
175
176
176 self.assertEqual(frames[0],
177 self.assertEqual(frames[0],
177 ffs(b'1 1 stream-begin command-request new '
178 ffs(b'1 1 stream-begin command-request new '
178 b"cbor:{b'name': b'foo', "
179 b"cbor:{b'name': b'foo', "
179 b"b'redirect': {b'targets': [b'a', b'b'], "
180 b"b'redirect': {b'targets': [b'a', b'b'], "
180 b"b'hashes': [b'sha256']}}"))
181 b"b'hashes': [b'sha256']}}"))
181
182
182 class StreamSettingsTests(unittest.TestCase):
183 class StreamSettingsTests(unittest.TestCase):
183 def testnoflags(self):
184 def testnoflags(self):
184 reactor = framing.clientreactor(globalui, buffersends=False)
185 reactor = framing.clientreactor(globalui, buffersends=False)
185
186
186 request, action, meta = reactor.callcommand(b'foo', {})
187 request, action, meta = reactor.callcommand(b'foo', {})
187 for f in meta[b'framegen']:
188 for f in meta[b'framegen']:
188 pass
189 pass
189
190
190 action, meta = sendframe(reactor,
191 action, meta = sendframe(reactor,
191 ffs(b'1 2 stream-begin stream-settings 0 '))
192 ffs(b'1 2 stream-begin stream-settings 0 '))
192
193
193 self.assertEqual(action, b'error')
194 self.assertEqual(action, b'error')
194 self.assertEqual(meta, {
195 self.assertEqual(meta, {
195 b'message': b'stream encoding settings frame must have '
196 b'message': b'stream encoding settings frame must have '
196 b'continuation or end of stream flag set',
197 b'continuation or end of stream flag set',
197 })
198 })
198
199
199 def testconflictflags(self):
200 def testconflictflags(self):
200 reactor = framing.clientreactor(globalui, buffersends=False)
201 reactor = framing.clientreactor(globalui, buffersends=False)
201
202
202 request, action, meta = reactor.callcommand(b'foo', {})
203 request, action, meta = reactor.callcommand(b'foo', {})
203 for f in meta[b'framegen']:
204 for f in meta[b'framegen']:
204 pass
205 pass
205
206
206 action, meta = sendframe(reactor,
207 action, meta = sendframe(reactor,
207 ffs(b'1 2 stream-begin stream-settings continuation|eos '))
208 ffs(b'1 2 stream-begin stream-settings continuation|eos '))
208
209
209 self.assertEqual(action, b'error')
210 self.assertEqual(action, b'error')
210 self.assertEqual(meta, {
211 self.assertEqual(meta, {
211 b'message': b'stream encoding settings frame cannot have both '
212 b'message': b'stream encoding settings frame cannot have both '
212 b'continuation and end of stream flags set',
213 b'continuation and end of stream flags set',
213 })
214 })
214
215
215 def testemptypayload(self):
216 def testemptypayload(self):
216 reactor = framing.clientreactor(globalui, buffersends=False)
217 reactor = framing.clientreactor(globalui, buffersends=False)
217
218
218 request, action, meta = reactor.callcommand(b'foo', {})
219 request, action, meta = reactor.callcommand(b'foo', {})
219 for f in meta[b'framegen']:
220 for f in meta[b'framegen']:
220 pass
221 pass
221
222
222 action, meta = sendframe(reactor,
223 action, meta = sendframe(reactor,
223 ffs(b'1 2 stream-begin stream-settings eos '))
224 ffs(b'1 2 stream-begin stream-settings eos '))
224
225
225 self.assertEqual(action, b'error')
226 self.assertEqual(action, b'error')
226 self.assertEqual(meta, {
227 self.assertEqual(meta, {
227 b'message': b'stream encoding settings frame did not contain '
228 b'message': b'stream encoding settings frame did not contain '
228 b'CBOR data'
229 b'CBOR data'
229 })
230 })
230
231
231 def testbadcbor(self):
232 def testbadcbor(self):
232 reactor = framing.clientreactor(globalui, buffersends=False)
233 reactor = framing.clientreactor(globalui, buffersends=False)
233
234
234 request, action, meta = reactor.callcommand(b'foo', {})
235 request, action, meta = reactor.callcommand(b'foo', {})
235 for f in meta[b'framegen']:
236 for f in meta[b'framegen']:
236 pass
237 pass
237
238
238 action, meta = sendframe(reactor,
239 action, meta = sendframe(reactor,
239 ffs(b'1 2 stream-begin stream-settings eos badvalue'))
240 ffs(b'1 2 stream-begin stream-settings eos badvalue'))
240
241
241 self.assertEqual(action, b'error')
242 self.assertEqual(action, b'error')
242
243
243 def testsingleobject(self):
244 def testsingleobject(self):
244 reactor = framing.clientreactor(globalui, buffersends=False)
245 reactor = framing.clientreactor(globalui, buffersends=False)
245
246
246 request, action, meta = reactor.callcommand(b'foo', {})
247 request, action, meta = reactor.callcommand(b'foo', {})
247 for f in meta[b'framegen']:
248 for f in meta[b'framegen']:
248 pass
249 pass
249
250
250 action, meta = sendframe(reactor,
251 action, meta = sendframe(reactor,
251 ffs(b'1 2 stream-begin stream-settings eos cbor:b"identity"'))
252 ffs(b'1 2 stream-begin stream-settings eos cbor:b"identity"'))
252
253
253 self.assertEqual(action, b'noop')
254 self.assertEqual(action, b'noop')
254 self.assertEqual(meta, {})
255 self.assertEqual(meta, {})
255
256
256 def testmultipleobjects(self):
257 def testmultipleobjects(self):
257 reactor = framing.clientreactor(globalui, buffersends=False)
258 reactor = framing.clientreactor(globalui, buffersends=False)
258
259
259 request, action, meta = reactor.callcommand(b'foo', {})
260 request, action, meta = reactor.callcommand(b'foo', {})
260 for f in meta[b'framegen']:
261 for f in meta[b'framegen']:
261 pass
262 pass
262
263
263 data = b''.join([
264 data = b''.join([
264 b''.join(cborutil.streamencode(b'identity')),
265 b''.join(cborutil.streamencode(b'identity')),
265 b''.join(cborutil.streamencode({b'foo', b'bar'})),
266 b''.join(cborutil.streamencode({b'foo', b'bar'})),
266 ])
267 ])
267
268
268 action, meta = sendframe(reactor,
269 action, meta = sendframe(reactor,
269 ffs(b'1 2 stream-begin stream-settings eos %s' % data))
270 ffs(b'1 2 stream-begin stream-settings eos %s' % data))
270
271
271 self.assertEqual(action, b'error')
272 self.assertEqual(action, b'error')
272 self.assertEqual(meta, {
273 self.assertEqual(meta, {
273 b'message': b'error setting stream decoder: identity decoder '
274 b'message': b'error setting stream decoder: identity decoder '
274 b'received unexpected additional values',
275 b'received unexpected additional values',
275 })
276 })
276
277
277 def testmultipleframes(self):
278 def testmultipleframes(self):
278 reactor = framing.clientreactor(globalui, buffersends=False)
279 reactor = framing.clientreactor(globalui, buffersends=False)
279
280
280 request, action, meta = reactor.callcommand(b'foo', {})
281 request, action, meta = reactor.callcommand(b'foo', {})
281 for f in meta[b'framegen']:
282 for f in meta[b'framegen']:
282 pass
283 pass
283
284
284 data = b''.join(cborutil.streamencode(b'identity'))
285 data = b''.join(cborutil.streamencode(b'identity'))
285
286
286 action, meta = sendframe(reactor,
287 action, meta = sendframe(reactor,
287 ffs(b'1 2 stream-begin stream-settings continuation %s' %
288 ffs(b'1 2 stream-begin stream-settings continuation %s' %
288 data[0:3]))
289 data[0:3]))
289
290
290 self.assertEqual(action, b'noop')
291 self.assertEqual(action, b'noop')
291 self.assertEqual(meta, {})
292 self.assertEqual(meta, {})
292
293
293 action, meta = sendframe(reactor,
294 action, meta = sendframe(reactor,
294 ffs(b'1 2 0 stream-settings eos %s' % data[3:]))
295 ffs(b'1 2 0 stream-settings eos %s' % data[3:]))
295
296
296 self.assertEqual(action, b'noop')
297 self.assertEqual(action, b'noop')
297 self.assertEqual(meta, {})
298 self.assertEqual(meta, {})
298
299
299 def testinvalidencoder(self):
300 def testinvalidencoder(self):
300 reactor = framing.clientreactor(globalui, buffersends=False)
301 reactor = framing.clientreactor(globalui, buffersends=False)
301
302
302 request, action, meta = reactor.callcommand(b'foo', {})
303 request, action, meta = reactor.callcommand(b'foo', {})
303 for f in meta[b'framegen']:
304 for f in meta[b'framegen']:
304 pass
305 pass
305
306
306 action, meta = sendframe(reactor,
307 action, meta = sendframe(reactor,
307 ffs(b'1 2 stream-begin stream-settings eos cbor:b"badvalue"'))
308 ffs(b'1 2 stream-begin stream-settings eos cbor:b"badvalue"'))
308
309
309 self.assertEqual(action, b'error')
310 self.assertEqual(action, b'error')
310 self.assertEqual(meta, {
311 self.assertEqual(meta, {
311 b'message': b'error setting stream decoder: unknown stream '
312 b'message': b'error setting stream decoder: unknown stream '
312 b'decoder: badvalue',
313 b'decoder: badvalue',
313 })
314 })
314
315
315 def testzlibencoding(self):
316 def testzlibencoding(self):
316 reactor = framing.clientreactor(globalui, buffersends=False)
317 reactor = framing.clientreactor(globalui, buffersends=False)
317
318
318 request, action, meta = reactor.callcommand(b'foo', {})
319 request, action, meta = reactor.callcommand(b'foo', {})
319 for f in meta[b'framegen']:
320 for f in meta[b'framegen']:
320 pass
321 pass
321
322
322 action, meta = sendframe(reactor,
323 action, meta = sendframe(reactor,
323 ffs(b'%d 2 stream-begin stream-settings eos cbor:b"zlib"' %
324 ffs(b'%d 2 stream-begin stream-settings eos cbor:b"zlib"' %
324 request.requestid))
325 request.requestid))
325
326
326 self.assertEqual(action, b'noop')
327 self.assertEqual(action, b'noop')
327 self.assertEqual(meta, {})
328 self.assertEqual(meta, {})
328
329
329 result = {
330 result = {
330 b'status': b'ok',
331 b'status': b'ok',
331 }
332 }
332 encoded = b''.join(cborutil.streamencode(result))
333 encoded = b''.join(cborutil.streamencode(result))
333
334
334 compressed = zlib.compress(encoded)
335 compressed = zlib.compress(encoded)
335 self.assertEqual(zlib.decompress(compressed), encoded)
336 self.assertEqual(zlib.decompress(compressed), encoded)
336
337
337 action, meta = sendframe(reactor,
338 action, meta = sendframe(reactor,
338 ffs(b'%d 2 encoded command-response eos %s' %
339 ffs(b'%d 2 encoded command-response eos %s' %
339 (request.requestid, compressed)))
340 (request.requestid, compressed)))
340
341
341 self.assertEqual(action, b'responsedata')
342 self.assertEqual(action, b'responsedata')
342 self.assertEqual(meta[b'data'], encoded)
343 self.assertEqual(meta[b'data'], encoded)
343
344
344 def testzlibencodingsinglebyteframes(self):
345 def testzlibencodingsinglebyteframes(self):
345 reactor = framing.clientreactor(globalui, buffersends=False)
346 reactor = framing.clientreactor(globalui, buffersends=False)
346
347
347 request, action, meta = reactor.callcommand(b'foo', {})
348 request, action, meta = reactor.callcommand(b'foo', {})
348 for f in meta[b'framegen']:
349 for f in meta[b'framegen']:
349 pass
350 pass
350
351
351 action, meta = sendframe(reactor,
352 action, meta = sendframe(reactor,
352 ffs(b'%d 2 stream-begin stream-settings eos cbor:b"zlib"' %
353 ffs(b'%d 2 stream-begin stream-settings eos cbor:b"zlib"' %
353 request.requestid))
354 request.requestid))
354
355
355 self.assertEqual(action, b'noop')
356 self.assertEqual(action, b'noop')
356 self.assertEqual(meta, {})
357 self.assertEqual(meta, {})
357
358
358 result = {
359 result = {
359 b'status': b'ok',
360 b'status': b'ok',
360 }
361 }
361 encoded = b''.join(cborutil.streamencode(result))
362 encoded = b''.join(cborutil.streamencode(result))
362
363
363 compressed = zlib.compress(encoded)
364 compressed = zlib.compress(encoded)
364 self.assertEqual(zlib.decompress(compressed), encoded)
365 self.assertEqual(zlib.decompress(compressed), encoded)
365
366
366 chunks = []
367 chunks = []
367
368
368 for i in range(len(compressed)):
369 for i in range(len(compressed)):
369 char = compressed[i:i + 1]
370 char = compressed[i:i + 1]
370 if char == b'\\':
371 if char == b'\\':
371 char = b'\\\\'
372 char = b'\\\\'
372 action, meta = sendframe(reactor,
373 action, meta = sendframe(reactor,
373 ffs(b'%d 2 encoded command-response continuation %s' %
374 ffs(b'%d 2 encoded command-response continuation %s' %
374 (request.requestid, char)))
375 (request.requestid, char)))
375
376
376 self.assertEqual(action, b'responsedata')
377 self.assertEqual(action, b'responsedata')
377 chunks.append(meta[b'data'])
378 chunks.append(meta[b'data'])
378 self.assertTrue(meta[b'expectmore'])
379 self.assertTrue(meta[b'expectmore'])
379 self.assertFalse(meta[b'eos'])
380 self.assertFalse(meta[b'eos'])
380
381
381 # zlib will have the full data decoded at this point, even though
382 # zlib will have the full data decoded at this point, even though
382 # we haven't flushed.
383 # we haven't flushed.
383 self.assertEqual(b''.join(chunks), encoded)
384 self.assertEqual(b''.join(chunks), encoded)
384
385
385 # End the stream for good measure.
386 # End the stream for good measure.
386 action, meta = sendframe(reactor,
387 action, meta = sendframe(reactor,
387 ffs(b'%d 2 stream-end command-response eos ' % request.requestid))
388 ffs(b'%d 2 stream-end command-response eos ' % request.requestid))
388
389
389 self.assertEqual(action, b'responsedata')
390 self.assertEqual(action, b'responsedata')
390 self.assertEqual(meta[b'data'], b'')
391 self.assertEqual(meta[b'data'], b'')
391 self.assertFalse(meta[b'expectmore'])
392 self.assertFalse(meta[b'expectmore'])
392 self.assertTrue(meta[b'eos'])
393 self.assertTrue(meta[b'eos'])
393
394
394 def testzlibmultipleresponses(self):
395 def testzlibmultipleresponses(self):
395 # We feed in zlib compressed data on the same stream but belonging to
396 # We feed in zlib compressed data on the same stream but belonging to
396 # 2 different requests. This tests our flushing behavior.
397 # 2 different requests. This tests our flushing behavior.
397 reactor = framing.clientreactor(globalui, buffersends=False,
398 reactor = framing.clientreactor(globalui, buffersends=False,
398 hasmultiplesend=True)
399 hasmultiplesend=True)
399
400
400 request1, action, meta = reactor.callcommand(b'foo', {})
401 request1, action, meta = reactor.callcommand(b'foo', {})
401 for f in meta[b'framegen']:
402 for f in meta[b'framegen']:
402 pass
403 pass
403
404
404 request2, action, meta = reactor.callcommand(b'foo', {})
405 request2, action, meta = reactor.callcommand(b'foo', {})
405 for f in meta[b'framegen']:
406 for f in meta[b'framegen']:
406 pass
407 pass
407
408
408 outstream = framing.outputstream(2)
409 outstream = framing.outputstream(2)
409 outstream.setencoder(globalui, b'zlib')
410 outstream.setencoder(globalui, b'zlib')
410
411
411 response1 = b''.join(cborutil.streamencode({
412 response1 = b''.join(cborutil.streamencode({
412 b'status': b'ok',
413 b'status': b'ok',
413 b'extra': b'response1' * 10,
414 b'extra': b'response1' * 10,
414 }))
415 }))
415
416
416 response2 = b''.join(cborutil.streamencode({
417 response2 = b''.join(cborutil.streamencode({
417 b'status': b'error',
418 b'status': b'error',
418 b'extra': b'response2' * 10,
419 b'extra': b'response2' * 10,
419 }))
420 }))
420
421
421 action, meta = sendframe(reactor,
422 action, meta = sendframe(reactor,
422 ffs(b'%d 2 stream-begin stream-settings eos cbor:b"zlib"' %
423 ffs(b'%d 2 stream-begin stream-settings eos cbor:b"zlib"' %
423 request1.requestid))
424 request1.requestid))
424
425
425 self.assertEqual(action, b'noop')
426 self.assertEqual(action, b'noop')
426 self.assertEqual(meta, {})
427 self.assertEqual(meta, {})
427
428
428 # Feeding partial data in won't get anything useful out.
429 # Feeding partial data in won't get anything useful out.
429 action, meta = sendframe(reactor,
430 action, meta = sendframe(reactor,
430 ffs(b'%d 2 encoded command-response continuation %s' % (
431 ffs(b'%d 2 encoded command-response continuation %s' % (
431 request1.requestid, outstream.encode(response1))))
432 request1.requestid, outstream.encode(response1))))
432 self.assertEqual(action, b'responsedata')
433 self.assertEqual(action, b'responsedata')
433 self.assertEqual(meta[b'data'], b'')
434 self.assertEqual(meta[b'data'], b'')
434
435
435 # But flushing data at both ends will get our original data.
436 # But flushing data at both ends will get our original data.
436 action, meta = sendframe(reactor,
437 action, meta = sendframe(reactor,
437 ffs(b'%d 2 encoded command-response eos %s' % (
438 ffs(b'%d 2 encoded command-response eos %s' % (
438 request1.requestid, outstream.flush())))
439 request1.requestid, outstream.flush())))
439 self.assertEqual(action, b'responsedata')
440 self.assertEqual(action, b'responsedata')
440 self.assertEqual(meta[b'data'], response1)
441 self.assertEqual(meta[b'data'], response1)
441
442
442 # We should be able to reuse the compressor/decompressor for the
443 # We should be able to reuse the compressor/decompressor for the
443 # 2nd response.
444 # 2nd response.
444 action, meta = sendframe(reactor,
445 action, meta = sendframe(reactor,
445 ffs(b'%d 2 encoded command-response continuation %s' % (
446 ffs(b'%d 2 encoded command-response continuation %s' % (
446 request2.requestid, outstream.encode(response2))))
447 request2.requestid, outstream.encode(response2))))
447 self.assertEqual(action, b'responsedata')
448 self.assertEqual(action, b'responsedata')
448 self.assertEqual(meta[b'data'], b'')
449 self.assertEqual(meta[b'data'], b'')
449
450
450 action, meta = sendframe(reactor,
451 action, meta = sendframe(reactor,
451 ffs(b'%d 2 encoded command-response eos %s' % (
452 ffs(b'%d 2 encoded command-response eos %s' % (
452 request2.requestid, outstream.flush())))
453 request2.requestid, outstream.flush())))
453 self.assertEqual(action, b'responsedata')
454 self.assertEqual(action, b'responsedata')
454 self.assertEqual(meta[b'data'], response2)
455 self.assertEqual(meta[b'data'], response2)
455
456
456 @unittest.skipUnless(zstd, 'zstd not available')
457 @unittest.skipUnless(zstd, 'zstd not available')
457 def testzstd8mbencoding(self):
458 def testzstd8mbencoding(self):
458 reactor = framing.clientreactor(globalui, buffersends=False)
459 reactor = framing.clientreactor(globalui, buffersends=False)
459
460
460 request, action, meta = reactor.callcommand(b'foo', {})
461 request, action, meta = reactor.callcommand(b'foo', {})
461 for f in meta[b'framegen']:
462 for f in meta[b'framegen']:
462 pass
463 pass
463
464
464 action, meta = sendframe(reactor,
465 action, meta = sendframe(reactor,
465 ffs(b'%d 2 stream-begin stream-settings eos cbor:b"zstd-8mb"' %
466 ffs(b'%d 2 stream-begin stream-settings eos cbor:b"zstd-8mb"' %
466 request.requestid))
467 request.requestid))
467
468
468 self.assertEqual(action, b'noop')
469 self.assertEqual(action, b'noop')
469 self.assertEqual(meta, {})
470 self.assertEqual(meta, {})
470
471
471 result = {
472 result = {
472 b'status': b'ok',
473 b'status': b'ok',
473 }
474 }
474 encoded = b''.join(cborutil.streamencode(result))
475 encoded = b''.join(cborutil.streamencode(result))
475
476
476 encoder = framing.zstd8mbencoder(globalui)
477 encoder = framing.zstd8mbencoder(globalui)
477 compressed = encoder.encode(encoded) + encoder.finish()
478 compressed = encoder.encode(encoded) + encoder.finish()
478 self.assertEqual(zstd.ZstdDecompressor().decompress(
479 self.assertEqual(zstd.ZstdDecompressor().decompress(
479 compressed, max_output_size=len(encoded)), encoded)
480 compressed, max_output_size=len(encoded)), encoded)
480
481
481 action, meta = sendframe(reactor,
482 action, meta = sendframe(reactor,
482 ffs(b'%d 2 encoded command-response eos %s' %
483 ffs(b'%d 2 encoded command-response eos %s' %
483 (request.requestid, compressed)))
484 (request.requestid, compressed)))
484
485
485 self.assertEqual(action, b'responsedata')
486 self.assertEqual(action, b'responsedata')
486 self.assertEqual(meta[b'data'], encoded)
487 self.assertEqual(meta[b'data'], encoded)
487
488
488 @unittest.skipUnless(zstd, 'zstd not available')
489 @unittest.skipUnless(zstd, 'zstd not available')
489 def testzstd8mbencodingsinglebyteframes(self):
490 def testzstd8mbencodingsinglebyteframes(self):
490 reactor = framing.clientreactor(globalui, buffersends=False)
491 reactor = framing.clientreactor(globalui, buffersends=False)
491
492
492 request, action, meta = reactor.callcommand(b'foo', {})
493 request, action, meta = reactor.callcommand(b'foo', {})
493 for f in meta[b'framegen']:
494 for f in meta[b'framegen']:
494 pass
495 pass
495
496
496 action, meta = sendframe(reactor,
497 action, meta = sendframe(reactor,
497 ffs(b'%d 2 stream-begin stream-settings eos cbor:b"zstd-8mb"' %
498 ffs(b'%d 2 stream-begin stream-settings eos cbor:b"zstd-8mb"' %
498 request.requestid))
499 request.requestid))
499
500
500 self.assertEqual(action, b'noop')
501 self.assertEqual(action, b'noop')
501 self.assertEqual(meta, {})
502 self.assertEqual(meta, {})
502
503
503 result = {
504 result = {
504 b'status': b'ok',
505 b'status': b'ok',
505 }
506 }
506 encoded = b''.join(cborutil.streamencode(result))
507 encoded = b''.join(cborutil.streamencode(result))
507
508
508 compressed = zstd.ZstdCompressor().compress(encoded)
509 compressed = zstd.ZstdCompressor().compress(encoded)
509 self.assertEqual(zstd.ZstdDecompressor().decompress(compressed),
510 self.assertEqual(zstd.ZstdDecompressor().decompress(compressed),
510 encoded)
511 encoded)
511
512
512 chunks = []
513 chunks = []
513
514
514 for i in range(len(compressed)):
515 for i in range(len(compressed)):
515 char = compressed[i:i + 1]
516 char = compressed[i:i + 1]
516 if char == b'\\':
517 if char == b'\\':
517 char = b'\\\\'
518 char = b'\\\\'
518 action, meta = sendframe(reactor,
519 action, meta = sendframe(reactor,
519 ffs(b'%d 2 encoded command-response continuation %s' %
520 ffs(b'%d 2 encoded command-response continuation %s' %
520 (request.requestid, char)))
521 (request.requestid, char)))
521
522
522 self.assertEqual(action, b'responsedata')
523 self.assertEqual(action, b'responsedata')
523 chunks.append(meta[b'data'])
524 chunks.append(meta[b'data'])
524 self.assertTrue(meta[b'expectmore'])
525 self.assertTrue(meta[b'expectmore'])
525 self.assertFalse(meta[b'eos'])
526 self.assertFalse(meta[b'eos'])
526
527
527 # zstd decompressor will flush at frame boundaries.
528 # zstd decompressor will flush at frame boundaries.
528 self.assertEqual(b''.join(chunks), encoded)
529 self.assertEqual(b''.join(chunks), encoded)
529
530
530 # End the stream for good measure.
531 # End the stream for good measure.
531 action, meta = sendframe(reactor,
532 action, meta = sendframe(reactor,
532 ffs(b'%d 2 stream-end command-response eos ' % request.requestid))
533 ffs(b'%d 2 stream-end command-response eos ' % request.requestid))
533
534
534 self.assertEqual(action, b'responsedata')
535 self.assertEqual(action, b'responsedata')
535 self.assertEqual(meta[b'data'], b'')
536 self.assertEqual(meta[b'data'], b'')
536 self.assertFalse(meta[b'expectmore'])
537 self.assertFalse(meta[b'expectmore'])
537 self.assertTrue(meta[b'eos'])
538 self.assertTrue(meta[b'eos'])
538
539
539 @unittest.skipUnless(zstd, 'zstd not available')
540 @unittest.skipUnless(zstd, 'zstd not available')
540 def testzstd8mbmultipleresponses(self):
541 def testzstd8mbmultipleresponses(self):
541 # We feed in zstd compressed data on the same stream but belonging to
542 # We feed in zstd compressed data on the same stream but belonging to
542 # 2 different requests. This tests our flushing behavior.
543 # 2 different requests. This tests our flushing behavior.
543 reactor = framing.clientreactor(globalui, buffersends=False,
544 reactor = framing.clientreactor(globalui, buffersends=False,
544 hasmultiplesend=True)
545 hasmultiplesend=True)
545
546
546 request1, action, meta = reactor.callcommand(b'foo', {})
547 request1, action, meta = reactor.callcommand(b'foo', {})
547 for f in meta[b'framegen']:
548 for f in meta[b'framegen']:
548 pass
549 pass
549
550
550 request2, action, meta = reactor.callcommand(b'foo', {})
551 request2, action, meta = reactor.callcommand(b'foo', {})
551 for f in meta[b'framegen']:
552 for f in meta[b'framegen']:
552 pass
553 pass
553
554
554 outstream = framing.outputstream(2)
555 outstream = framing.outputstream(2)
555 outstream.setencoder(globalui, b'zstd-8mb')
556 outstream.setencoder(globalui, b'zstd-8mb')
556
557
557 response1 = b''.join(cborutil.streamencode({
558 response1 = b''.join(cborutil.streamencode({
558 b'status': b'ok',
559 b'status': b'ok',
559 b'extra': b'response1' * 10,
560 b'extra': b'response1' * 10,
560 }))
561 }))
561
562
562 response2 = b''.join(cborutil.streamencode({
563 response2 = b''.join(cborutil.streamencode({
563 b'status': b'error',
564 b'status': b'error',
564 b'extra': b'response2' * 10,
565 b'extra': b'response2' * 10,
565 }))
566 }))
566
567
567 action, meta = sendframe(reactor,
568 action, meta = sendframe(reactor,
568 ffs(b'%d 2 stream-begin stream-settings eos cbor:b"zstd-8mb"' %
569 ffs(b'%d 2 stream-begin stream-settings eos cbor:b"zstd-8mb"' %
569 request1.requestid))
570 request1.requestid))
570
571
571 self.assertEqual(action, b'noop')
572 self.assertEqual(action, b'noop')
572 self.assertEqual(meta, {})
573 self.assertEqual(meta, {})
573
574
574 # Feeding partial data in won't get anything useful out.
575 # Feeding partial data in won't get anything useful out.
575 action, meta = sendframe(reactor,
576 action, meta = sendframe(reactor,
576 ffs(b'%d 2 encoded command-response continuation %s' % (
577 ffs(b'%d 2 encoded command-response continuation %s' % (
577 request1.requestid, outstream.encode(response1))))
578 request1.requestid, outstream.encode(response1))))
578 self.assertEqual(action, b'responsedata')
579 self.assertEqual(action, b'responsedata')
579 self.assertEqual(meta[b'data'], b'')
580 self.assertEqual(meta[b'data'], b'')
580
581
581 # But flushing data at both ends will get our original data.
582 # But flushing data at both ends will get our original data.
582 action, meta = sendframe(reactor,
583 action, meta = sendframe(reactor,
583 ffs(b'%d 2 encoded command-response eos %s' % (
584 ffs(b'%d 2 encoded command-response eos %s' % (
584 request1.requestid, outstream.flush())))
585 request1.requestid, outstream.flush())))
585 self.assertEqual(action, b'responsedata')
586 self.assertEqual(action, b'responsedata')
586 self.assertEqual(meta[b'data'], response1)
587 self.assertEqual(meta[b'data'], response1)
587
588
588 # We should be able to reuse the compressor/decompressor for the
589 # We should be able to reuse the compressor/decompressor for the
589 # 2nd response.
590 # 2nd response.
590 action, meta = sendframe(reactor,
591 action, meta = sendframe(reactor,
591 ffs(b'%d 2 encoded command-response continuation %s' % (
592 ffs(b'%d 2 encoded command-response continuation %s' % (
592 request2.requestid, outstream.encode(response2))))
593 request2.requestid, outstream.encode(response2))))
593 self.assertEqual(action, b'responsedata')
594 self.assertEqual(action, b'responsedata')
594 self.assertEqual(meta[b'data'], b'')
595 self.assertEqual(meta[b'data'], b'')
595
596
596 action, meta = sendframe(reactor,
597 action, meta = sendframe(reactor,
597 ffs(b'%d 2 encoded command-response eos %s' % (
598 ffs(b'%d 2 encoded command-response eos %s' % (
598 request2.requestid, outstream.flush())))
599 request2.requestid, outstream.flush())))
599 self.assertEqual(action, b'responsedata')
600 self.assertEqual(action, b'responsedata')
600 self.assertEqual(meta[b'data'], response2)
601 self.assertEqual(meta[b'data'], response2)
601
602
602 if __name__ == '__main__':
603 if __name__ == '__main__':
604 if (3, 6, 0) <= sys.version_info <= (3, 6, 3):
605 # Python 3.6.0 through 3.6.3 inclusive shipped with
606 # https://bugs.python.org/issue31825 and we can't run these
607 # tests on those specific versions of Python. Sigh.
608 sys.exit(80)
603 import silenttestrunner
609 import silenttestrunner
604 silenttestrunner.main(__name__)
610 silenttestrunner.main(__name__)
General Comments 0
You need to be logged in to leave comments. Login now