65 reactor = makereactor() |
70 reactor = makereactor() |
66 stream = framing.stream(1) |
71 stream = framing.stream(1) |
67 results = list(sendcommandframes(reactor, stream, 1, b'mycommand', {})) |
72 results = list(sendcommandframes(reactor, stream, 1, b'mycommand', {})) |
68 self.assertEqual(len(results), 1) |
73 self.assertEqual(len(results), 1) |
69 self.assertaction(results[0], b'runcommand') |
74 self.assertaction(results[0], b'runcommand') |
70 self.assertEqual(results[0][1], { |
75 self.assertEqual( |
71 b'requestid': 1, |
76 results[0][1], |
72 b'command': b'mycommand', |
77 { |
73 b'args': {}, |
78 b'requestid': 1, |
74 b'redirect': None, |
79 b'command': b'mycommand', |
75 b'data': None, |
80 b'args': {}, |
76 }) |
81 b'redirect': None, |
|
82 b'data': None, |
|
83 }, |
|
84 ) |
77 |
85 |
78 result = reactor.oninputeof() |
86 result = reactor.oninputeof() |
79 self.assertaction(result, b'noop') |
87 self.assertaction(result, b'noop') |
80 |
88 |
81 def test1argument(self): |
89 def test1argument(self): |
82 reactor = makereactor() |
90 reactor = makereactor() |
83 stream = framing.stream(1) |
91 stream = framing.stream(1) |
84 results = list(sendcommandframes(reactor, stream, 41, b'mycommand', |
92 results = list( |
85 {b'foo': b'bar'})) |
93 sendcommandframes( |
|
94 reactor, stream, 41, b'mycommand', {b'foo': b'bar'} |
|
95 ) |
|
96 ) |
86 self.assertEqual(len(results), 1) |
97 self.assertEqual(len(results), 1) |
87 self.assertaction(results[0], b'runcommand') |
98 self.assertaction(results[0], b'runcommand') |
88 self.assertEqual(results[0][1], { |
99 self.assertEqual( |
89 b'requestid': 41, |
100 results[0][1], |
90 b'command': b'mycommand', |
101 { |
91 b'args': {b'foo': b'bar'}, |
102 b'requestid': 41, |
92 b'redirect': None, |
103 b'command': b'mycommand', |
93 b'data': None, |
104 b'args': {b'foo': b'bar'}, |
94 }) |
105 b'redirect': None, |
|
106 b'data': None, |
|
107 }, |
|
108 ) |
95 |
109 |
96 def testmultiarguments(self): |
110 def testmultiarguments(self): |
97 reactor = makereactor() |
111 reactor = makereactor() |
98 stream = framing.stream(1) |
112 stream = framing.stream(1) |
99 results = list(sendcommandframes(reactor, stream, 1, b'mycommand', |
113 results = list( |
100 {b'foo': b'bar', b'biz': b'baz'})) |
114 sendcommandframes( |
|
115 reactor, |
|
116 stream, |
|
117 1, |
|
118 b'mycommand', |
|
119 {b'foo': b'bar', b'biz': b'baz'}, |
|
120 ) |
|
121 ) |
101 self.assertEqual(len(results), 1) |
122 self.assertEqual(len(results), 1) |
102 self.assertaction(results[0], b'runcommand') |
123 self.assertaction(results[0], b'runcommand') |
103 self.assertEqual(results[0][1], { |
124 self.assertEqual( |
104 b'requestid': 1, |
125 results[0][1], |
105 b'command': b'mycommand', |
126 { |
106 b'args': {b'foo': b'bar', b'biz': b'baz'}, |
127 b'requestid': 1, |
107 b'redirect': None, |
128 b'command': b'mycommand', |
108 b'data': None, |
129 b'args': {b'foo': b'bar', b'biz': b'baz'}, |
109 }) |
130 b'redirect': None, |
|
131 b'data': None, |
|
132 }, |
|
133 ) |
110 |
134 |
111 def testsimplecommanddata(self): |
135 def testsimplecommanddata(self): |
112 reactor = makereactor() |
136 reactor = makereactor() |
113 stream = framing.stream(1) |
137 stream = framing.stream(1) |
114 results = list(sendcommandframes(reactor, stream, 1, b'mycommand', {}, |
138 results = list( |
115 util.bytesio(b'data!'))) |
139 sendcommandframes( |
|
140 reactor, stream, 1, b'mycommand', {}, util.bytesio(b'data!') |
|
141 ) |
|
142 ) |
116 self.assertEqual(len(results), 2) |
143 self.assertEqual(len(results), 2) |
117 self.assertaction(results[0], b'wantframe') |
144 self.assertaction(results[0], b'wantframe') |
118 self.assertaction(results[1], b'runcommand') |
145 self.assertaction(results[1], b'runcommand') |
119 self.assertEqual(results[1][1], { |
146 self.assertEqual( |
120 b'requestid': 1, |
147 results[1][1], |
121 b'command': b'mycommand', |
148 { |
122 b'args': {}, |
149 b'requestid': 1, |
123 b'redirect': None, |
150 b'command': b'mycommand', |
124 b'data': b'data!', |
151 b'args': {}, |
125 }) |
152 b'redirect': None, |
|
153 b'data': b'data!', |
|
154 }, |
|
155 ) |
126 |
156 |
127 def testmultipledataframes(self): |
157 def testmultipledataframes(self): |
128 frames = [ |
158 frames = [ |
129 ffs(b'1 1 stream-begin command-request new|have-data ' |
159 ffs( |
130 b"cbor:{b'name': b'mycommand'}"), |
160 b'1 1 stream-begin command-request new|have-data ' |
|
161 b"cbor:{b'name': b'mycommand'}" |
|
162 ), |
131 ffs(b'1 1 0 command-data continuation data1'), |
163 ffs(b'1 1 0 command-data continuation data1'), |
132 ffs(b'1 1 0 command-data continuation data2'), |
164 ffs(b'1 1 0 command-data continuation data2'), |
133 ffs(b'1 1 0 command-data eos data3'), |
165 ffs(b'1 1 0 command-data eos data3'), |
134 ] |
166 ] |
135 |
167 |
137 results = list(sendframes(reactor, frames)) |
169 results = list(sendframes(reactor, frames)) |
138 self.assertEqual(len(results), 4) |
170 self.assertEqual(len(results), 4) |
139 for i in range(3): |
171 for i in range(3): |
140 self.assertaction(results[i], b'wantframe') |
172 self.assertaction(results[i], b'wantframe') |
141 self.assertaction(results[3], b'runcommand') |
173 self.assertaction(results[3], b'runcommand') |
142 self.assertEqual(results[3][1], { |
174 self.assertEqual( |
143 b'requestid': 1, |
175 results[3][1], |
144 b'command': b'mycommand', |
176 { |
145 b'args': {}, |
177 b'requestid': 1, |
146 b'redirect': None, |
178 b'command': b'mycommand', |
147 b'data': b'data1data2data3', |
179 b'args': {}, |
148 }) |
180 b'redirect': None, |
|
181 b'data': b'data1data2data3', |
|
182 }, |
|
183 ) |
149 |
184 |
150 def testargumentanddata(self): |
185 def testargumentanddata(self): |
151 frames = [ |
186 frames = [ |
152 ffs(b'1 1 stream-begin command-request new|have-data ' |
187 ffs( |
|
188 b'1 1 stream-begin command-request new|have-data ' |
153 b"cbor:{b'name': b'command', b'args': {b'key': b'val'," |
189 b"cbor:{b'name': b'command', b'args': {b'key': b'val'," |
154 b"b'foo': b'bar'}}"), |
190 b"b'foo': b'bar'}}" |
|
191 ), |
155 ffs(b'1 1 0 command-data continuation value1'), |
192 ffs(b'1 1 0 command-data continuation value1'), |
156 ffs(b'1 1 0 command-data eos value2'), |
193 ffs(b'1 1 0 command-data eos value2'), |
157 ] |
194 ] |
158 |
195 |
159 reactor = makereactor() |
196 reactor = makereactor() |
160 results = list(sendframes(reactor, frames)) |
197 results = list(sendframes(reactor, frames)) |
161 |
198 |
162 self.assertaction(results[-1], b'runcommand') |
199 self.assertaction(results[-1], b'runcommand') |
163 self.assertEqual(results[-1][1], { |
200 self.assertEqual( |
164 b'requestid': 1, |
201 results[-1][1], |
165 b'command': b'command', |
202 { |
166 b'args': { |
203 b'requestid': 1, |
167 b'key': b'val', |
204 b'command': b'command', |
168 b'foo': b'bar', |
205 b'args': {b'key': b'val', b'foo': b'bar',}, |
169 }, |
206 b'redirect': None, |
170 b'redirect': None, |
207 b'data': b'value1value2', |
171 b'data': b'value1value2', |
208 }, |
172 }) |
209 ) |
173 |
210 |
174 def testnewandcontinuation(self): |
211 def testnewandcontinuation(self): |
175 result = self._sendsingleframe(makereactor(), |
212 result = self._sendsingleframe( |
176 ffs(b'1 1 stream-begin command-request new|continuation ')) |
213 makereactor(), |
|
214 ffs(b'1 1 stream-begin command-request new|continuation '), |
|
215 ) |
177 self.assertaction(result, b'error') |
216 self.assertaction(result, b'error') |
178 self.assertEqual(result[1], { |
217 self.assertEqual( |
179 b'message': b'received command request frame with both new and ' |
218 result[1], |
180 b'continuation flags set', |
219 { |
181 }) |
220 b'message': b'received command request frame with both new and ' |
|
221 b'continuation flags set', |
|
222 }, |
|
223 ) |
182 |
224 |
183 def testneithernewnorcontinuation(self): |
225 def testneithernewnorcontinuation(self): |
184 result = self._sendsingleframe(makereactor(), |
226 result = self._sendsingleframe( |
185 ffs(b'1 1 stream-begin command-request 0 ')) |
227 makereactor(), ffs(b'1 1 stream-begin command-request 0 ') |
|
228 ) |
186 self.assertaction(result, b'error') |
229 self.assertaction(result, b'error') |
187 self.assertEqual(result[1], { |
230 self.assertEqual( |
188 b'message': b'received command request frame with neither new nor ' |
231 result[1], |
189 b'continuation flags set', |
232 { |
190 }) |
233 b'message': b'received command request frame with neither new nor ' |
|
234 b'continuation flags set', |
|
235 }, |
|
236 ) |
191 |
237 |
192 def testunexpectedcommanddata(self): |
238 def testunexpectedcommanddata(self): |
193 """Command data frame when not running a command is an error.""" |
239 """Command data frame when not running a command is an error.""" |
194 result = self._sendsingleframe(makereactor(), |
240 result = self._sendsingleframe( |
195 ffs(b'1 1 stream-begin command-data 0 ignored')) |
241 makereactor(), ffs(b'1 1 stream-begin command-data 0 ignored') |
|
242 ) |
196 self.assertaction(result, b'error') |
243 self.assertaction(result, b'error') |
197 self.assertEqual(result[1], { |
244 self.assertEqual( |
198 b'message': b'expected sender protocol settings or command request ' |
245 result[1], |
199 b'frame; got 2', |
246 { |
200 }) |
247 b'message': b'expected sender protocol settings or command request ' |
|
248 b'frame; got 2', |
|
249 }, |
|
250 ) |
201 |
251 |
202 def testunexpectedcommanddatareceiving(self): |
252 def testunexpectedcommanddatareceiving(self): |
203 """Same as above except the command is receiving.""" |
253 """Same as above except the command is receiving.""" |
204 results = list(sendframes(makereactor(), [ |
254 results = list( |
205 ffs(b'1 1 stream-begin command-request new|more ' |
255 sendframes( |
206 b"cbor:{b'name': b'ignored'}"), |
256 makereactor(), |
207 ffs(b'1 1 0 command-data eos ignored'), |
257 [ |
208 ])) |
258 ffs( |
|
259 b'1 1 stream-begin command-request new|more ' |
|
260 b"cbor:{b'name': b'ignored'}" |
|
261 ), |
|
262 ffs(b'1 1 0 command-data eos ignored'), |
|
263 ], |
|
264 ) |
|
265 ) |
209 |
266 |
210 self.assertaction(results[0], b'wantframe') |
267 self.assertaction(results[0], b'wantframe') |
211 self.assertaction(results[1], b'error') |
268 self.assertaction(results[1], b'error') |
212 self.assertEqual(results[1][1], { |
269 self.assertEqual( |
213 b'message': b'received command data frame for request that is not ' |
270 results[1][1], |
214 b'expecting data: 1', |
271 { |
215 }) |
272 b'message': b'received command data frame for request that is not ' |
|
273 b'expecting data: 1', |
|
274 }, |
|
275 ) |
216 |
276 |
217 def testconflictingrequestidallowed(self): |
277 def testconflictingrequestidallowed(self): |
218 """Multiple fully serviced commands with same request ID is allowed.""" |
278 """Multiple fully serviced commands with same request ID is allowed.""" |
219 reactor = makereactor() |
279 reactor = makereactor() |
220 results = [] |
280 results = [] |
221 outstream = reactor.makeoutputstream() |
281 outstream = reactor.makeoutputstream() |
222 results.append(self._sendsingleframe( |
282 results.append( |
223 reactor, ffs(b'1 1 stream-begin command-request new ' |
283 self._sendsingleframe( |
224 b"cbor:{b'name': b'command'}"))) |
284 reactor, |
|
285 ffs( |
|
286 b'1 1 stream-begin command-request new ' |
|
287 b"cbor:{b'name': b'command'}" |
|
288 ), |
|
289 ) |
|
290 ) |
225 result = reactor.oncommandresponsereadyobjects( |
291 result = reactor.oncommandresponsereadyobjects( |
226 outstream, 1, [b'response1']) |
292 outstream, 1, [b'response1'] |
|
293 ) |
227 self.assertaction(result, b'sendframes') |
294 self.assertaction(result, b'sendframes') |
228 list(result[1][b'framegen']) |
295 list(result[1][b'framegen']) |
229 results.append(self._sendsingleframe( |
296 results.append( |
230 reactor, ffs(b'1 1 stream-begin command-request new ' |
297 self._sendsingleframe( |
231 b"cbor:{b'name': b'command'}"))) |
298 reactor, |
|
299 ffs( |
|
300 b'1 1 stream-begin command-request new ' |
|
301 b"cbor:{b'name': b'command'}" |
|
302 ), |
|
303 ) |
|
304 ) |
232 result = reactor.oncommandresponsereadyobjects( |
305 result = reactor.oncommandresponsereadyobjects( |
233 outstream, 1, [b'response2']) |
306 outstream, 1, [b'response2'] |
|
307 ) |
234 self.assertaction(result, b'sendframes') |
308 self.assertaction(result, b'sendframes') |
235 list(result[1][b'framegen']) |
309 list(result[1][b'framegen']) |
236 results.append(self._sendsingleframe( |
310 results.append( |
237 reactor, ffs(b'1 1 stream-begin command-request new ' |
311 self._sendsingleframe( |
238 b"cbor:{b'name': b'command'}"))) |
312 reactor, |
|
313 ffs( |
|
314 b'1 1 stream-begin command-request new ' |
|
315 b"cbor:{b'name': b'command'}" |
|
316 ), |
|
317 ) |
|
318 ) |
239 result = reactor.oncommandresponsereadyobjects( |
319 result = reactor.oncommandresponsereadyobjects( |
240 outstream, 1, [b'response3']) |
320 outstream, 1, [b'response3'] |
|
321 ) |
241 self.assertaction(result, b'sendframes') |
322 self.assertaction(result, b'sendframes') |
242 list(result[1][b'framegen']) |
323 list(result[1][b'framegen']) |
243 |
324 |
244 for i in range(3): |
325 for i in range(3): |
245 self.assertaction(results[i], b'runcommand') |
326 self.assertaction(results[i], b'runcommand') |
246 self.assertEqual(results[i][1], { |
327 self.assertEqual( |
247 b'requestid': 1, |
328 results[i][1], |
248 b'command': b'command', |
329 { |
249 b'args': {}, |
330 b'requestid': 1, |
|
331 b'command': b'command', |
|
332 b'args': {}, |
|
333 b'redirect': None, |
|
334 b'data': None, |
|
335 }, |
|
336 ) |
|
337 |
|
338 def testconflictingrequestid(self): |
|
339 """Request ID for new command matching in-flight command is illegal.""" |
|
340 results = list( |
|
341 sendframes( |
|
342 makereactor(), |
|
343 [ |
|
344 ffs( |
|
345 b'1 1 stream-begin command-request new|more ' |
|
346 b"cbor:{b'name': b'command'}" |
|
347 ), |
|
348 ffs( |
|
349 b'1 1 0 command-request new ' |
|
350 b"cbor:{b'name': b'command1'}" |
|
351 ), |
|
352 ], |
|
353 ) |
|
354 ) |
|
355 |
|
356 self.assertaction(results[0], b'wantframe') |
|
357 self.assertaction(results[1], b'error') |
|
358 self.assertEqual( |
|
359 results[1][1], {b'message': b'request with ID 1 already received',} |
|
360 ) |
|
361 |
|
362 def testinterleavedcommands(self): |
|
363 cbor1 = b''.join( |
|
364 cborutil.streamencode( |
|
365 { |
|
366 b'name': b'command1', |
|
367 b'args': {b'foo': b'bar', b'key1': b'val',}, |
|
368 } |
|
369 ) |
|
370 ) |
|
371 cbor3 = b''.join( |
|
372 cborutil.streamencode( |
|
373 { |
|
374 b'name': b'command3', |
|
375 b'args': {b'biz': b'baz', b'key': b'val',}, |
|
376 } |
|
377 ) |
|
378 ) |
|
379 |
|
380 results = list( |
|
381 sendframes( |
|
382 makereactor(), |
|
383 [ |
|
384 ffs( |
|
385 b'1 1 stream-begin command-request new|more %s' |
|
386 % cbor1[0:6] |
|
387 ), |
|
388 ffs(b'3 1 0 command-request new|more %s' % cbor3[0:10]), |
|
389 ffs( |
|
390 b'1 1 0 command-request continuation|more %s' |
|
391 % cbor1[6:9] |
|
392 ), |
|
393 ffs( |
|
394 b'3 1 0 command-request continuation|more %s' |
|
395 % cbor3[10:13] |
|
396 ), |
|
397 ffs(b'3 1 0 command-request continuation %s' % cbor3[13:]), |
|
398 ffs(b'1 1 0 command-request continuation %s' % cbor1[9:]), |
|
399 ], |
|
400 ) |
|
401 ) |
|
402 |
|
403 self.assertEqual( |
|
404 [t[0] for t in results], |
|
405 [ |
|
406 b'wantframe', |
|
407 b'wantframe', |
|
408 b'wantframe', |
|
409 b'wantframe', |
|
410 b'runcommand', |
|
411 b'runcommand', |
|
412 ], |
|
413 ) |
|
414 |
|
415 self.assertEqual( |
|
416 results[4][1], |
|
417 { |
|
418 b'requestid': 3, |
|
419 b'command': b'command3', |
|
420 b'args': {b'biz': b'baz', b'key': b'val'}, |
250 b'redirect': None, |
421 b'redirect': None, |
251 b'data': None, |
422 b'data': None, |
252 }) |
423 }, |
253 |
424 ) |
254 def testconflictingrequestid(self): |
425 self.assertEqual( |
255 """Request ID for new command matching in-flight command is illegal.""" |
426 results[5][1], |
256 results = list(sendframes(makereactor(), [ |
427 { |
257 ffs(b'1 1 stream-begin command-request new|more ' |
428 b'requestid': 1, |
258 b"cbor:{b'name': b'command'}"), |
429 b'command': b'command1', |
259 ffs(b'1 1 0 command-request new ' |
430 b'args': {b'foo': b'bar', b'key1': b'val'}, |
260 b"cbor:{b'name': b'command1'}"), |
431 b'redirect': None, |
261 ])) |
432 b'data': None, |
262 |
433 }, |
263 self.assertaction(results[0], b'wantframe') |
434 ) |
264 self.assertaction(results[1], b'error') |
|
265 self.assertEqual(results[1][1], { |
|
266 b'message': b'request with ID 1 already received', |
|
267 }) |
|
268 |
|
269 def testinterleavedcommands(self): |
|
270 cbor1 = b''.join(cborutil.streamencode({ |
|
271 b'name': b'command1', |
|
272 b'args': { |
|
273 b'foo': b'bar', |
|
274 b'key1': b'val', |
|
275 } |
|
276 })) |
|
277 cbor3 = b''.join(cborutil.streamencode({ |
|
278 b'name': b'command3', |
|
279 b'args': { |
|
280 b'biz': b'baz', |
|
281 b'key': b'val', |
|
282 }, |
|
283 })) |
|
284 |
|
285 results = list(sendframes(makereactor(), [ |
|
286 ffs(b'1 1 stream-begin command-request new|more %s' % cbor1[0:6]), |
|
287 ffs(b'3 1 0 command-request new|more %s' % cbor3[0:10]), |
|
288 ffs(b'1 1 0 command-request continuation|more %s' % cbor1[6:9]), |
|
289 ffs(b'3 1 0 command-request continuation|more %s' % cbor3[10:13]), |
|
290 ffs(b'3 1 0 command-request continuation %s' % cbor3[13:]), |
|
291 ffs(b'1 1 0 command-request continuation %s' % cbor1[9:]), |
|
292 ])) |
|
293 |
|
294 self.assertEqual([t[0] for t in results], [ |
|
295 b'wantframe', |
|
296 b'wantframe', |
|
297 b'wantframe', |
|
298 b'wantframe', |
|
299 b'runcommand', |
|
300 b'runcommand', |
|
301 ]) |
|
302 |
|
303 self.assertEqual(results[4][1], { |
|
304 b'requestid': 3, |
|
305 b'command': b'command3', |
|
306 b'args': {b'biz': b'baz', b'key': b'val'}, |
|
307 b'redirect': None, |
|
308 b'data': None, |
|
309 }) |
|
310 self.assertEqual(results[5][1], { |
|
311 b'requestid': 1, |
|
312 b'command': b'command1', |
|
313 b'args': {b'foo': b'bar', b'key1': b'val'}, |
|
314 b'redirect': None, |
|
315 b'data': None, |
|
316 }) |
|
317 |
435 |
318 def testmissingcommanddataframe(self): |
436 def testmissingcommanddataframe(self): |
319 # The reactor doesn't currently handle partially received commands. |
437 # The reactor doesn't currently handle partially received commands. |
320 # So this test is failing to do anything with request 1. |
438 # So this test is failing to do anything with request 1. |
321 frames = [ |
439 frames = [ |
322 ffs(b'1 1 stream-begin command-request new|have-data ' |
440 ffs( |
323 b"cbor:{b'name': b'command1'}"), |
441 b'1 1 stream-begin command-request new|have-data ' |
324 ffs(b'3 1 0 command-request new ' |
442 b"cbor:{b'name': b'command1'}" |
325 b"cbor:{b'name': b'command2'}"), |
443 ), |
|
444 ffs(b'3 1 0 command-request new ' b"cbor:{b'name': b'command2'}"), |
326 ] |
445 ] |
327 results = list(sendframes(makereactor(), frames)) |
446 results = list(sendframes(makereactor(), frames)) |
328 self.assertEqual(len(results), 2) |
447 self.assertEqual(len(results), 2) |
329 self.assertaction(results[0], b'wantframe') |
448 self.assertaction(results[0], b'wantframe') |
330 self.assertaction(results[1], b'runcommand') |
449 self.assertaction(results[1], b'runcommand') |
331 |
450 |
332 def testmissingcommanddataframeflags(self): |
451 def testmissingcommanddataframeflags(self): |
333 frames = [ |
452 frames = [ |
334 ffs(b'1 1 stream-begin command-request new|have-data ' |
453 ffs( |
335 b"cbor:{b'name': b'command1'}"), |
454 b'1 1 stream-begin command-request new|have-data ' |
|
455 b"cbor:{b'name': b'command1'}" |
|
456 ), |
336 ffs(b'1 1 0 command-data 0 data'), |
457 ffs(b'1 1 0 command-data 0 data'), |
337 ] |
458 ] |
338 results = list(sendframes(makereactor(), frames)) |
459 results = list(sendframes(makereactor(), frames)) |
339 self.assertEqual(len(results), 2) |
460 self.assertEqual(len(results), 2) |
340 self.assertaction(results[0], b'wantframe') |
461 self.assertaction(results[0], b'wantframe') |
341 self.assertaction(results[1], b'error') |
462 self.assertaction(results[1], b'error') |
342 self.assertEqual(results[1][1], { |
463 self.assertEqual( |
343 b'message': b'command data frame without flags', |
464 results[1][1], {b'message': b'command data frame without flags',} |
344 }) |
465 ) |
345 |
466 |
346 def testframefornonreceivingrequest(self): |
467 def testframefornonreceivingrequest(self): |
347 """Receiving a frame for a command that is not receiving is illegal.""" |
468 """Receiving a frame for a command that is not receiving is illegal.""" |
348 results = list(sendframes(makereactor(), [ |
469 results = list( |
349 ffs(b'1 1 stream-begin command-request new ' |
470 sendframes( |
350 b"cbor:{b'name': b'command1'}"), |
471 makereactor(), |
351 ffs(b'3 1 0 command-request new|have-data ' |
472 [ |
352 b"cbor:{b'name': b'command3'}"), |
473 ffs( |
353 ffs(b'5 1 0 command-data eos ignored'), |
474 b'1 1 stream-begin command-request new ' |
354 ])) |
475 b"cbor:{b'name': b'command1'}" |
|
476 ), |
|
477 ffs( |
|
478 b'3 1 0 command-request new|have-data ' |
|
479 b"cbor:{b'name': b'command3'}" |
|
480 ), |
|
481 ffs(b'5 1 0 command-data eos ignored'), |
|
482 ], |
|
483 ) |
|
484 ) |
355 self.assertaction(results[2], b'error') |
485 self.assertaction(results[2], b'error') |
356 self.assertEqual(results[2][1], { |
486 self.assertEqual( |
357 b'message': b'received frame for request that is not receiving: 5', |
487 results[2][1], |
358 }) |
488 { |
|
489 b'message': b'received frame for request that is not receiving: 5', |
|
490 }, |
|
491 ) |
359 |
492 |
360 def testsimpleresponse(self): |
493 def testsimpleresponse(self): |
361 """Bytes response to command sends result frames.""" |
494 """Bytes response to command sends result frames.""" |
362 reactor = makereactor() |
495 reactor = makereactor() |
363 instream = framing.stream(1) |
496 instream = framing.stream(1) |
364 list(sendcommandframes(reactor, instream, 1, b'mycommand', {})) |
497 list(sendcommandframes(reactor, instream, 1, b'mycommand', {})) |
365 |
498 |
366 outstream = reactor.makeoutputstream() |
499 outstream = reactor.makeoutputstream() |
367 result = reactor.oncommandresponsereadyobjects( |
500 result = reactor.oncommandresponsereadyobjects( |
368 outstream, 1, [b'response']) |
501 outstream, 1, [b'response'] |
|
502 ) |
369 self.assertaction(result, b'sendframes') |
503 self.assertaction(result, b'sendframes') |
370 self.assertframesequal(result[1][b'framegen'], [ |
504 self.assertframesequal( |
371 b'1 2 stream-begin stream-settings eos cbor:b"identity"', |
505 result[1][b'framegen'], |
372 b'1 2 encoded command-response continuation %s' % OK, |
506 [ |
373 b'1 2 encoded command-response continuation cbor:b"response"', |
507 b'1 2 stream-begin stream-settings eos cbor:b"identity"', |
374 b'1 2 0 command-response eos ', |
508 b'1 2 encoded command-response continuation %s' % OK, |
375 ]) |
509 b'1 2 encoded command-response continuation cbor:b"response"', |
|
510 b'1 2 0 command-response eos ', |
|
511 ], |
|
512 ) |
376 |
513 |
377 def testmultiframeresponse(self): |
514 def testmultiframeresponse(self): |
378 """Bytes response spanning multiple frames is handled.""" |
515 """Bytes response spanning multiple frames is handled.""" |
379 first = b'x' * framing.DEFAULT_MAX_FRAME_SIZE |
516 first = b'x' * framing.DEFAULT_MAX_FRAME_SIZE |
380 second = b'y' * 100 |
517 second = b'y' * 100 |
383 instream = framing.stream(1) |
520 instream = framing.stream(1) |
384 list(sendcommandframes(reactor, instream, 1, b'mycommand', {})) |
521 list(sendcommandframes(reactor, instream, 1, b'mycommand', {})) |
385 |
522 |
386 outstream = reactor.makeoutputstream() |
523 outstream = reactor.makeoutputstream() |
387 result = reactor.oncommandresponsereadyobjects( |
524 result = reactor.oncommandresponsereadyobjects( |
388 outstream, 1, [first + second]) |
525 outstream, 1, [first + second] |
|
526 ) |
389 self.assertaction(result, b'sendframes') |
527 self.assertaction(result, b'sendframes') |
390 self.assertframesequal(result[1][b'framegen'], [ |
528 self.assertframesequal( |
391 b'1 2 stream-begin stream-settings eos cbor:b"identity"', |
529 result[1][b'framegen'], |
392 b'1 2 encoded command-response continuation %s' % OK, |
530 [ |
393 b'1 2 encoded command-response continuation Y\x80d', |
531 b'1 2 stream-begin stream-settings eos cbor:b"identity"', |
394 b'1 2 encoded command-response continuation %s' % first, |
532 b'1 2 encoded command-response continuation %s' % OK, |
395 b'1 2 encoded command-response continuation %s' % second, |
533 b'1 2 encoded command-response continuation Y\x80d', |
396 b'1 2 0 command-response eos ' |
534 b'1 2 encoded command-response continuation %s' % first, |
397 ]) |
535 b'1 2 encoded command-response continuation %s' % second, |
|
536 b'1 2 0 command-response eos ', |
|
537 ], |
|
538 ) |
398 |
539 |
399 def testservererror(self): |
540 def testservererror(self): |
400 reactor = makereactor() |
541 reactor = makereactor() |
401 instream = framing.stream(1) |
542 instream = framing.stream(1) |
402 list(sendcommandframes(reactor, instream, 1, b'mycommand', {})) |
543 list(sendcommandframes(reactor, instream, 1, b'mycommand', {})) |
403 |
544 |
404 outstream = reactor.makeoutputstream() |
545 outstream = reactor.makeoutputstream() |
405 result = reactor.onservererror(outstream, 1, b'some message') |
546 result = reactor.onservererror(outstream, 1, b'some message') |
406 self.assertaction(result, b'sendframes') |
547 self.assertaction(result, b'sendframes') |
407 self.assertframesequal(result[1][b'framegen'], [ |
548 self.assertframesequal( |
408 b"1 2 stream-begin error-response 0 " |
549 result[1][b'framegen'], |
409 b"cbor:{b'type': b'server', " |
550 [ |
410 b"b'message': [{b'msg': b'some message'}]}", |
551 b"1 2 stream-begin error-response 0 " |
411 ]) |
552 b"cbor:{b'type': b'server', " |
|
553 b"b'message': [{b'msg': b'some message'}]}", |
|
554 ], |
|
555 ) |
412 |
556 |
413 def test1commanddeferresponse(self): |
557 def test1commanddeferresponse(self): |
414 """Responses when in deferred output mode are delayed until EOF.""" |
558 """Responses when in deferred output mode are delayed until EOF.""" |
415 reactor = makereactor(deferoutput=True) |
559 reactor = makereactor(deferoutput=True) |
416 instream = framing.stream(1) |
560 instream = framing.stream(1) |
417 results = list(sendcommandframes(reactor, instream, 1, b'mycommand', |
561 results = list( |
418 {})) |
562 sendcommandframes(reactor, instream, 1, b'mycommand', {}) |
|
563 ) |
419 self.assertEqual(len(results), 1) |
564 self.assertEqual(len(results), 1) |
420 self.assertaction(results[0], b'runcommand') |
565 self.assertaction(results[0], b'runcommand') |
421 |
566 |
422 outstream = reactor.makeoutputstream() |
567 outstream = reactor.makeoutputstream() |
423 result = reactor.oncommandresponsereadyobjects( |
568 result = reactor.oncommandresponsereadyobjects( |
424 outstream, 1, [b'response']) |
569 outstream, 1, [b'response'] |
|
570 ) |
425 self.assertaction(result, b'noop') |
571 self.assertaction(result, b'noop') |
426 result = reactor.oninputeof() |
572 result = reactor.oninputeof() |
427 self.assertaction(result, b'sendframes') |
573 self.assertaction(result, b'sendframes') |
428 self.assertframesequal(result[1][b'framegen'], [ |
574 self.assertframesequal( |
429 b'1 2 stream-begin stream-settings eos cbor:b"identity"', |
575 result[1][b'framegen'], |
430 b'1 2 encoded command-response continuation %s' % OK, |
576 [ |
431 b'1 2 encoded command-response continuation cbor:b"response"', |
577 b'1 2 stream-begin stream-settings eos cbor:b"identity"', |
432 b'1 2 0 command-response eos ', |
578 b'1 2 encoded command-response continuation %s' % OK, |
433 ]) |
579 b'1 2 encoded command-response continuation cbor:b"response"', |
|
580 b'1 2 0 command-response eos ', |
|
581 ], |
|
582 ) |
434 |
583 |
435 def testmultiplecommanddeferresponse(self): |
584 def testmultiplecommanddeferresponse(self): |
436 reactor = makereactor(deferoutput=True) |
585 reactor = makereactor(deferoutput=True) |
437 instream = framing.stream(1) |
586 instream = framing.stream(1) |
438 list(sendcommandframes(reactor, instream, 1, b'command1', {})) |
587 list(sendcommandframes(reactor, instream, 1, b'command1', {})) |
439 list(sendcommandframes(reactor, instream, 3, b'command2', {})) |
588 list(sendcommandframes(reactor, instream, 3, b'command2', {})) |
440 |
589 |
441 outstream = reactor.makeoutputstream() |
590 outstream = reactor.makeoutputstream() |
442 result = reactor.oncommandresponsereadyobjects( |
591 result = reactor.oncommandresponsereadyobjects( |
443 outstream, 1, [b'response1']) |
592 outstream, 1, [b'response1'] |
|
593 ) |
444 self.assertaction(result, b'noop') |
594 self.assertaction(result, b'noop') |
445 result = reactor.oncommandresponsereadyobjects( |
595 result = reactor.oncommandresponsereadyobjects( |
446 outstream, 3, [b'response2']) |
596 outstream, 3, [b'response2'] |
|
597 ) |
447 self.assertaction(result, b'noop') |
598 self.assertaction(result, b'noop') |
448 result = reactor.oninputeof() |
599 result = reactor.oninputeof() |
449 self.assertaction(result, b'sendframes') |
600 self.assertaction(result, b'sendframes') |
450 self.assertframesequal(result[1][b'framegen'], [ |
601 self.assertframesequal( |
451 b'1 2 stream-begin stream-settings eos cbor:b"identity"', |
602 result[1][b'framegen'], |
452 b'1 2 encoded command-response continuation %s' % OK, |
603 [ |
453 b'1 2 encoded command-response continuation cbor:b"response1"', |
604 b'1 2 stream-begin stream-settings eos cbor:b"identity"', |
454 b'1 2 0 command-response eos ', |
605 b'1 2 encoded command-response continuation %s' % OK, |
455 b'3 2 encoded command-response continuation %s' % OK, |
606 b'1 2 encoded command-response continuation cbor:b"response1"', |
456 b'3 2 encoded command-response continuation cbor:b"response2"', |
607 b'1 2 0 command-response eos ', |
457 b'3 2 0 command-response eos ', |
608 b'3 2 encoded command-response continuation %s' % OK, |
458 ]) |
609 b'3 2 encoded command-response continuation cbor:b"response2"', |
|
610 b'3 2 0 command-response eos ', |
|
611 ], |
|
612 ) |
459 |
613 |
460 def testrequestidtracking(self): |
614 def testrequestidtracking(self): |
461 reactor = makereactor(deferoutput=True) |
615 reactor = makereactor(deferoutput=True) |
462 instream = framing.stream(1) |
616 instream = framing.stream(1) |
463 list(sendcommandframes(reactor, instream, 1, b'command1', {})) |
617 list(sendcommandframes(reactor, instream, 1, b'command1', {})) |
470 reactor.oncommandresponsereadyobjects(outstream, 1, [b'response1']) |
624 reactor.oncommandresponsereadyobjects(outstream, 1, [b'response1']) |
471 reactor.oncommandresponsereadyobjects(outstream, 5, [b'response5']) |
625 reactor.oncommandresponsereadyobjects(outstream, 5, [b'response5']) |
472 |
626 |
473 result = reactor.oninputeof() |
627 result = reactor.oninputeof() |
474 self.assertaction(result, b'sendframes') |
628 self.assertaction(result, b'sendframes') |
475 self.assertframesequal(result[1][b'framegen'], [ |
629 self.assertframesequal( |
476 b'3 2 stream-begin stream-settings eos cbor:b"identity"', |
630 result[1][b'framegen'], |
477 b'3 2 encoded command-response continuation %s' % OK, |
631 [ |
478 b'3 2 encoded command-response continuation cbor:b"response3"', |
632 b'3 2 stream-begin stream-settings eos cbor:b"identity"', |
479 b'3 2 0 command-response eos ', |
633 b'3 2 encoded command-response continuation %s' % OK, |
480 b'1 2 encoded command-response continuation %s' % OK, |
634 b'3 2 encoded command-response continuation cbor:b"response3"', |
481 b'1 2 encoded command-response continuation cbor:b"response1"', |
635 b'3 2 0 command-response eos ', |
482 b'1 2 0 command-response eos ', |
636 b'1 2 encoded command-response continuation %s' % OK, |
483 b'5 2 encoded command-response continuation %s' % OK, |
637 b'1 2 encoded command-response continuation cbor:b"response1"', |
484 b'5 2 encoded command-response continuation cbor:b"response5"', |
638 b'1 2 0 command-response eos ', |
485 b'5 2 0 command-response eos ', |
639 b'5 2 encoded command-response continuation %s' % OK, |
486 ]) |
640 b'5 2 encoded command-response continuation cbor:b"response5"', |
|
641 b'5 2 0 command-response eos ', |
|
642 ], |
|
643 ) |
487 |
644 |
488 def testduplicaterequestonactivecommand(self): |
645 def testduplicaterequestonactivecommand(self): |
489 """Receiving a request ID that matches a request that isn't finished.""" |
646 """Receiving a request ID that matches a request that isn't finished.""" |
490 reactor = makereactor() |
647 reactor = makereactor() |
491 stream = framing.stream(1) |
648 stream = framing.stream(1) |
492 list(sendcommandframes(reactor, stream, 1, b'command1', {})) |
649 list(sendcommandframes(reactor, stream, 1, b'command1', {})) |
493 results = list(sendcommandframes(reactor, stream, 1, b'command1', {})) |
650 results = list(sendcommandframes(reactor, stream, 1, b'command1', {})) |
494 |
651 |
495 self.assertaction(results[0], b'error') |
652 self.assertaction(results[0], b'error') |
496 self.assertEqual(results[0][1], { |
653 self.assertEqual( |
497 b'message': b'request with ID 1 is already active', |
654 results[0][1], {b'message': b'request with ID 1 is already active',} |
498 }) |
655 ) |
499 |
656 |
500 def testduplicaterequestonactivecommandnosend(self): |
657 def testduplicaterequestonactivecommandnosend(self): |
501 """Same as above but we've registered a response but haven't sent it.""" |
658 """Same as above but we've registered a response but haven't sent it.""" |
502 reactor = makereactor() |
659 reactor = makereactor() |
503 instream = framing.stream(1) |
660 instream = framing.stream(1) |
526 results = list(sendcommandframes(reactor, instream, 1, b'command1', {})) |
683 results = list(sendcommandframes(reactor, instream, 1, b'command1', {})) |
527 self.assertaction(results[0], b'runcommand') |
684 self.assertaction(results[0], b'runcommand') |
528 |
685 |
529 def testprotocolsettingsnoflags(self): |
686 def testprotocolsettingsnoflags(self): |
530 result = self._sendsingleframe( |
687 result = self._sendsingleframe( |
|
688 makereactor(), ffs(b'0 1 stream-begin sender-protocol-settings 0 ') |
|
689 ) |
|
690 self.assertaction(result, b'error') |
|
691 self.assertEqual( |
|
692 result[1], |
|
693 { |
|
694 b'message': b'sender protocol settings frame must have ' |
|
695 b'continuation or end of stream flag set', |
|
696 }, |
|
697 ) |
|
698 |
|
699 def testprotocolsettingsconflictflags(self): |
|
700 result = self._sendsingleframe( |
531 makereactor(), |
701 makereactor(), |
532 ffs(b'0 1 stream-begin sender-protocol-settings 0 ')) |
702 ffs(b'0 1 stream-begin sender-protocol-settings continuation|eos '), |
|
703 ) |
533 self.assertaction(result, b'error') |
704 self.assertaction(result, b'error') |
534 self.assertEqual(result[1], { |
705 self.assertEqual( |
535 b'message': b'sender protocol settings frame must have ' |
706 result[1], |
536 b'continuation or end of stream flag set', |
707 { |
537 }) |
708 b'message': b'sender protocol settings frame cannot have both ' |
538 |
709 b'continuation and end of stream flags set', |
539 def testprotocolsettingsconflictflags(self): |
710 }, |
|
711 ) |
|
712 |
|
713 def testprotocolsettingsemptypayload(self): |
540 result = self._sendsingleframe( |
714 result = self._sendsingleframe( |
541 makereactor(), |
715 makereactor(), |
542 ffs(b'0 1 stream-begin sender-protocol-settings continuation|eos ')) |
716 ffs(b'0 1 stream-begin sender-protocol-settings eos '), |
|
717 ) |
543 self.assertaction(result, b'error') |
718 self.assertaction(result, b'error') |
544 self.assertEqual(result[1], { |
719 self.assertEqual( |
545 b'message': b'sender protocol settings frame cannot have both ' |
720 result[1], |
546 b'continuation and end of stream flags set', |
721 { |
547 }) |
722 b'message': b'sender protocol settings frame did not contain CBOR ' |
548 |
723 b'data', |
549 def testprotocolsettingsemptypayload(self): |
724 }, |
|
725 ) |
|
726 |
|
727 def testprotocolsettingsmultipleobjects(self): |
550 result = self._sendsingleframe( |
728 result = self._sendsingleframe( |
551 makereactor(), |
729 makereactor(), |
552 ffs(b'0 1 stream-begin sender-protocol-settings eos ')) |
730 ffs( |
|
731 b'0 1 stream-begin sender-protocol-settings eos ' |
|
732 b'\x46foobar\x43foo' |
|
733 ), |
|
734 ) |
553 self.assertaction(result, b'error') |
735 self.assertaction(result, b'error') |
554 self.assertEqual(result[1], { |
736 self.assertEqual( |
555 b'message': b'sender protocol settings frame did not contain CBOR ' |
737 result[1], |
556 b'data', |
738 { |
557 }) |
739 b'message': b'sender protocol settings frame contained multiple ' |
558 |
740 b'CBOR values', |
559 def testprotocolsettingsmultipleobjects(self): |
741 }, |
560 result = self._sendsingleframe( |
742 ) |
561 makereactor(), |
|
562 ffs(b'0 1 stream-begin sender-protocol-settings eos ' |
|
563 b'\x46foobar\x43foo')) |
|
564 self.assertaction(result, b'error') |
|
565 self.assertEqual(result[1], { |
|
566 b'message': b'sender protocol settings frame contained multiple ' |
|
567 b'CBOR values', |
|
568 }) |
|
569 |
743 |
570 def testprotocolsettingscontentencodings(self): |
744 def testprotocolsettingscontentencodings(self): |
571 reactor = makereactor() |
745 reactor = makereactor() |
572 |
746 |
573 result = self._sendsingleframe( |
747 result = self._sendsingleframe( |
574 reactor, |
748 reactor, |
575 ffs(b'0 1 stream-begin sender-protocol-settings eos ' |
749 ffs( |
576 b'cbor:{b"contentencodings": [b"a", b"b"]}')) |
750 b'0 1 stream-begin sender-protocol-settings eos ' |
|
751 b'cbor:{b"contentencodings": [b"a", b"b"]}' |
|
752 ), |
|
753 ) |
577 self.assertaction(result, b'wantframe') |
754 self.assertaction(result, b'wantframe') |
578 |
755 |
579 self.assertEqual(reactor._state, b'idle') |
756 self.assertEqual(reactor._state, b'idle') |
580 self.assertEqual(reactor._sendersettings[b'contentencodings'], |
757 self.assertEqual( |
581 [b'a', b'b']) |
758 reactor._sendersettings[b'contentencodings'], [b'a', b'b'] |
|
759 ) |
582 |
760 |
583 def testprotocolsettingsmultipleframes(self): |
761 def testprotocolsettingsmultipleframes(self): |
584 reactor = makereactor() |
762 reactor = makereactor() |
585 |
763 |
586 data = b''.join(cborutil.streamencode({ |
764 data = b''.join( |
587 b'contentencodings': [b'value1', b'value2'], |
765 cborutil.streamencode( |
588 })) |
766 {b'contentencodings': [b'value1', b'value2'],} |
589 |
767 ) |
590 results = list(sendframes(reactor, [ |
768 ) |
591 ffs(b'0 1 stream-begin sender-protocol-settings continuation %s' % |
769 |
592 data[0:5]), |
770 results = list( |
593 ffs(b'0 1 0 sender-protocol-settings eos %s' % data[5:]), |
771 sendframes( |
594 ])) |
772 reactor, |
|
773 [ |
|
774 ffs( |
|
775 b'0 1 stream-begin sender-protocol-settings continuation %s' |
|
776 % data[0:5] |
|
777 ), |
|
778 ffs(b'0 1 0 sender-protocol-settings eos %s' % data[5:]), |
|
779 ], |
|
780 ) |
|
781 ) |
595 |
782 |
596 self.assertEqual(len(results), 2) |
783 self.assertEqual(len(results), 2) |
597 |
784 |
598 self.assertaction(results[0], b'wantframe') |
785 self.assertaction(results[0], b'wantframe') |
599 self.assertaction(results[1], b'wantframe') |
786 self.assertaction(results[1], b'wantframe') |
600 |
787 |
601 self.assertEqual(reactor._state, b'idle') |
788 self.assertEqual(reactor._state, b'idle') |
602 self.assertEqual(reactor._sendersettings[b'contentencodings'], |
789 self.assertEqual( |
603 [b'value1', b'value2']) |
790 reactor._sendersettings[b'contentencodings'], [b'value1', b'value2'] |
|
791 ) |
604 |
792 |
605 def testprotocolsettingsbadcbor(self): |
793 def testprotocolsettingsbadcbor(self): |
606 result = self._sendsingleframe( |
794 result = self._sendsingleframe( |
607 makereactor(), |
795 makereactor(), |
608 ffs(b'0 1 stream-begin sender-protocol-settings eos badvalue')) |
796 ffs(b'0 1 stream-begin sender-protocol-settings eos badvalue'), |
|
797 ) |
609 self.assertaction(result, b'error') |
798 self.assertaction(result, b'error') |
610 |
799 |
611 def testprotocolsettingsnoninitial(self): |
800 def testprotocolsettingsnoninitial(self): |
612 # Cannot have protocol settings frames as non-initial frames. |
801 # Cannot have protocol settings frames as non-initial frames. |
613 reactor = makereactor() |
802 reactor = makereactor() |