OLD | NEW |
| (Empty) |
1 # Copyright (c) 2007 Twisted Matrix Laboratories. | |
2 # See LICENSE for details | |
3 | |
4 """ | |
5 This module tests twisted.conch.ssh.connection. | |
6 """ | |
7 import struct | |
8 from twisted.conch import error | |
9 from twisted.conch.ssh import channel, common, connection | |
10 from twisted.trial import unittest | |
11 from twisted.conch.test import test_userauth | |
12 | |
13 class TestChannel(channel.SSHChannel): | |
14 """ | |
15 A mocked-up version of twisted.conch.ssh.channel.SSHChannel. | |
16 | |
17 @ivar gotOpen: True if channelOpen has been called. | |
18 @type gotOpen: C{bool} | |
19 @ivar specificData: the specific channel open data passed to channelOpen. | |
20 @type specificData: C{str} | |
21 @ivar openFailureReason: the reason passed to openFailed. | |
22 @type openFailed: C{error.ConchError} | |
23 @ivar inBuffer: a C{list} of strings received by the channel. | |
24 @type inBuffer: C{list} | |
25 @ivar extBuffer: a C{list} of 2-tuples (type, extended data) of received by | |
26 the channel. | |
27 @type extBuffer: C{list} | |
28 @ivar numberRequests: the number of requests that have been made to this | |
29 channel. | |
30 @type numberRequests: C{int} | |
31 @ivar gotEOF: True if the other side sent EOF. | |
32 @type gotEOF: C{bool} | |
33 @ivar gotOneClose: True if the other side closed the connection. | |
34 @type gotOneClose: C{bool} | |
35 @ivar gotClosed: True if the channel is closed. | |
36 @type gotClosed: C{bool} | |
37 """ | |
38 name = "TestChannel" | |
39 gotOpen = False | |
40 | |
41 def logPrefix(self): | |
42 return "TestChannel %i" % self.id | |
43 | |
44 def channelOpen(self, specificData): | |
45 """ | |
46 The channel is open. Set up the instance variables. | |
47 """ | |
48 self.gotOpen = True | |
49 self.specificData = specificData | |
50 self.inBuffer = [] | |
51 self.extBuffer = [] | |
52 self.numberRequests = 0 | |
53 self.gotEOF = False | |
54 self.gotOneClose = False | |
55 self.gotClosed = False | |
56 | |
57 def openFailed(self, reason): | |
58 """ | |
59 Opening the channel failed. Store the reason why. | |
60 """ | |
61 self.openFailureReason = reason | |
62 | |
63 def request_test(self, data): | |
64 """ | |
65 A test request. Return True if data is 'data'. | |
66 | |
67 @type data: C{str} | |
68 """ | |
69 self.numberRequests += 1 | |
70 return data == 'data' | |
71 | |
72 def dataReceived(self, data): | |
73 """ | |
74 Data was received. Store it in the buffer. | |
75 """ | |
76 self.inBuffer.append(data) | |
77 | |
78 def extReceived(self, code, data): | |
79 """ | |
80 Extended data was received. Store it in the buffer. | |
81 """ | |
82 self.extBuffer.append((code, data)) | |
83 | |
84 def eofReceived(self): | |
85 """ | |
86 EOF was received. Remember it. | |
87 """ | |
88 self.gotEOF = True | |
89 | |
90 def closeReceived(self): | |
91 """ | |
92 Close was received. Remember it. | |
93 """ | |
94 self.gotOneClose = True | |
95 | |
96 def closed(self): | |
97 """ | |
98 The channel is closed. Rembember it. | |
99 """ | |
100 self.gotClosed = True | |
101 | |
102 class TestAvatar: | |
103 """ | |
104 A mocked-up version of twisted.conch.avatar.ConchUser | |
105 """ | |
106 | |
107 def lookupChannel(self, channelType, windowSize, maxPacket, data): | |
108 """ | |
109 The server wants us to return a channel. If the requested channel is | |
110 our TestChannel, return it, otherwise return None. | |
111 """ | |
112 if channelType == TestChannel.name: | |
113 return TestChannel(remoteWindow=windowSize, | |
114 remoteMaxPacket=maxPacket, | |
115 data=data, avatar=self) | |
116 | |
117 def gotGlobalRequest(self, requestType, data): | |
118 """ | |
119 The client has made a global request. If the global request is | |
120 'TestGlobal', return True. If the global request is 'TestData', | |
121 return True and the request-specific data we received. Otherwise, | |
122 return False. | |
123 """ | |
124 if requestType == 'TestGlobal': | |
125 return True | |
126 elif requestType == 'TestData': | |
127 return True, data | |
128 else: | |
129 return False | |
130 | |
131 class TestConnection(connection.SSHConnection): | |
132 """ | |
133 A subclass of SSHConnection for testing. | |
134 | |
135 @ivar channel: the current channel. | |
136 @type channel. C{TestChannel} | |
137 """ | |
138 | |
139 def logPrefix(self): | |
140 return "TestConnection" | |
141 | |
142 def global_TestGlobal(self, data): | |
143 """ | |
144 The other side made the 'TestGlobal' global request. Return True. | |
145 """ | |
146 return True | |
147 | |
148 def global_Test_Data(self, data): | |
149 """ | |
150 The other side made the 'Test-Data' global request. Return True and | |
151 the data we received. | |
152 """ | |
153 return True, data | |
154 | |
155 def channel_TestChannel(self, windowSize, maxPacket, data): | |
156 """ | |
157 The other side is requesting the TestChannel. Create a C{TestChannel} | |
158 instance, store it, and return it. | |
159 """ | |
160 self.channel = TestChannel(remoteWindow=windowSize, | |
161 remoteMaxPacket=maxPacket, data=data) | |
162 return self.channel | |
163 | |
164 def channel_ErrorChannel(self, windowSize, maxPacket, data): | |
165 """ | |
166 The other side is requesting the ErrorChannel. Raise an exception. | |
167 """ | |
168 raise AssertionError('no such thing') | |
169 | |
170 class ConnectionTestCase(unittest.TestCase): | |
171 | |
172 def setUp(self): | |
173 self.transport = test_userauth.FakeTransport(None) | |
174 self.transport.avatar = TestAvatar() | |
175 self.conn = TestConnection() | |
176 self.conn.transport = self.transport | |
177 self.conn.serviceStarted() | |
178 | |
179 def _openChannel(self, channel): | |
180 """ | |
181 Open the channel with the default connection. | |
182 """ | |
183 self.conn.openChannel(channel) | |
184 self.transport.packets = self.transport.packets[:-1] | |
185 self.conn.ssh_CHANNEL_OPEN_CONFIRMATION(struct.pack('>2L', | |
186 channel.id, 255) + '\x00\x02\x00\x00\x00\x00\x80\x00') | |
187 | |
188 def tearDown(self): | |
189 self.conn.serviceStopped() | |
190 | |
191 def test_linkAvatar(self): | |
192 """ | |
193 Test that the connection links itself to the avatar in the | |
194 transport. | |
195 """ | |
196 self.assertIdentical(self.transport.avatar.conn, self.conn) | |
197 | |
198 def test_serviceStopped(self): | |
199 """ | |
200 Test that serviceStopped() closes any open channels. | |
201 """ | |
202 channel1 = TestChannel() | |
203 channel2 = TestChannel() | |
204 self.conn.openChannel(channel1) | |
205 self.conn.openChannel(channel2) | |
206 self.conn.ssh_CHANNEL_OPEN_CONFIRMATION('\x00\x00\x00\x00' * 4) | |
207 self.assertTrue(channel1.gotOpen) | |
208 self.assertFalse(channel2.gotOpen) | |
209 self.conn.serviceStopped() | |
210 self.assertTrue(channel1.gotClosed) | |
211 | |
212 def test_GLOBAL_REQUEST(self): | |
213 """ | |
214 Test that global request packets are dispatched to the global_* | |
215 methods and the return values are translated into success or failure | |
216 messages. | |
217 """ | |
218 self.conn.ssh_GLOBAL_REQUEST(common.NS('TestGlobal') + '\xff') | |
219 self.assertEquals(self.transport.packets, | |
220 [(connection.MSG_REQUEST_SUCCESS, '')]) | |
221 self.transport.packets = [] | |
222 self.conn.ssh_GLOBAL_REQUEST(common.NS('TestData') + '\xff' + | |
223 'test data') | |
224 self.assertEquals(self.transport.packets, | |
225 [(connection.MSG_REQUEST_SUCCESS, 'test data')]) | |
226 self.transport.packets = [] | |
227 self.conn.ssh_GLOBAL_REQUEST(common.NS('TestBad') + '\xff') | |
228 self.assertEquals(self.transport.packets, | |
229 [(connection.MSG_REQUEST_FAILURE, '')]) | |
230 self.transport.packets = [] | |
231 self.conn.ssh_GLOBAL_REQUEST(common.NS('TestGlobal') + '\x00') | |
232 self.assertEquals(self.transport.packets, []) | |
233 | |
234 def test_REQUEST_SUCCESS(self): | |
235 """ | |
236 Test that global request success packets cause the Deferred to be | |
237 called back. | |
238 """ | |
239 d = self.conn.sendGlobalRequest('request', 'data', True) | |
240 self.conn.ssh_REQUEST_SUCCESS('data') | |
241 def check(data): | |
242 self.assertEquals(data, 'data') | |
243 d.addCallback(check) | |
244 d.addErrback(self.fail) | |
245 return d | |
246 | |
247 def test_REQUEST_FAILURE(self): | |
248 """ | |
249 Test that global request failure packets cause the Deferred to be | |
250 erred back. | |
251 """ | |
252 d = self.conn.sendGlobalRequest('request', 'data', True) | |
253 self.conn.ssh_REQUEST_FAILURE('data') | |
254 def check(f): | |
255 self.assertEquals(f.value.data, 'data') | |
256 d.addCallback(self.fail) | |
257 d.addErrback(check) | |
258 return d | |
259 | |
260 def test_CHANNEL_OPEN(self): | |
261 """ | |
262 Test that open channel packets cause a channel to be created and | |
263 opened or a failure message to be returned. | |
264 """ | |
265 del self.transport.avatar | |
266 self.conn.ssh_CHANNEL_OPEN(common.NS('TestChannel') + | |
267 '\x00\x00\x00\x01' * 4) | |
268 self.assertTrue(self.conn.channel.gotOpen) | |
269 self.assertEquals(self.conn.channel.conn, self.conn) | |
270 self.assertEquals(self.conn.channel.data, '\x00\x00\x00\x01') | |
271 self.assertEquals(self.conn.channel.specificData, '\x00\x00\x00\x01') | |
272 self.assertEquals(self.conn.channel.remoteWindowLeft, 1) | |
273 self.assertEquals(self.conn.channel.remoteMaxPacket, 1) | |
274 self.assertEquals(self.transport.packets, | |
275 [(connection.MSG_CHANNEL_OPEN_CONFIRMATION, | |
276 '\x00\x00\x00\x01\x00\x00\x00\x00\x00\x02\x00\x00' | |
277 '\x00\x00\x80\x00')]) | |
278 self.transport.packets = [] | |
279 self.conn.ssh_CHANNEL_OPEN(common.NS('BadChannel') + | |
280 '\x00\x00\x00\x02' * 4) | |
281 self.flushLoggedErrors() | |
282 self.assertEquals(self.transport.packets, | |
283 [(connection.MSG_CHANNEL_OPEN_FAILURE, | |
284 '\x00\x00\x00\x02\x00\x00\x00\x03' + common.NS( | |
285 'unknown channel') + common.NS(''))]) | |
286 self.transport.packets = [] | |
287 self.conn.ssh_CHANNEL_OPEN(common.NS('ErrorChannel') + | |
288 '\x00\x00\x00\x02' * 4) | |
289 self.flushLoggedErrors() | |
290 self.assertEquals(self.transport.packets, | |
291 [(connection.MSG_CHANNEL_OPEN_FAILURE, | |
292 '\x00\x00\x00\x02\x00\x00\x00\x02' + common.NS( | |
293 'unknown failure') + common.NS(''))]) | |
294 | |
295 def test_CHANNEL_OPEN_CONFIRMATION(self): | |
296 """ | |
297 Test that channel open confirmation packets cause the channel to be | |
298 notified that it's open. | |
299 """ | |
300 channel = TestChannel() | |
301 self.conn.openChannel(channel) | |
302 self.conn.ssh_CHANNEL_OPEN_CONFIRMATION('\x00\x00\x00\x00'*5) | |
303 self.assertEquals(channel.remoteWindowLeft, 0) | |
304 self.assertEquals(channel.remoteMaxPacket, 0) | |
305 self.assertEquals(channel.specificData, '\x00\x00\x00\x00') | |
306 self.assertEquals(self.conn.channelsToRemoteChannel[channel], | |
307 0) | |
308 self.assertEquals(self.conn.localToRemoteChannel[0], 0) | |
309 | |
310 def test_CHANNEL_OPEN_FAILURE(self): | |
311 """ | |
312 Test that channel open failure packets cause the channel to be | |
313 notified that its opening failed. | |
314 """ | |
315 channel = TestChannel() | |
316 self.conn.openChannel(channel) | |
317 self.conn.ssh_CHANNEL_OPEN_FAILURE('\x00\x00\x00\x00\x00\x00\x00' | |
318 '\x01' + common.NS('failure!')) | |
319 self.assertEquals(channel.openFailureReason.args, ('failure!', 1)) | |
320 self.assertEquals(self.conn.channels.get(channel), None) | |
321 | |
322 | |
323 def test_CHANNEL_WINDOW_ADJUST(self): | |
324 """ | |
325 Test that channel window adjust messages add bytes to the channel | |
326 window. | |
327 """ | |
328 channel = TestChannel() | |
329 self._openChannel(channel) | |
330 oldWindowSize = channel.remoteWindowLeft | |
331 self.conn.ssh_CHANNEL_WINDOW_ADJUST('\x00\x00\x00\x00\x00\x00\x00' | |
332 '\x01') | |
333 self.assertEquals(channel.remoteWindowLeft, oldWindowSize + 1) | |
334 | |
335 def test_CHANNEL_DATA(self): | |
336 """ | |
337 Test that channel data messages are passed up to the channel, or | |
338 cause the channel to be closed if the data is too large. | |
339 """ | |
340 channel = TestChannel(localWindow=6, localMaxPacket=5) | |
341 self._openChannel(channel) | |
342 self.conn.ssh_CHANNEL_DATA('\x00\x00\x00\x00' + common.NS('data')) | |
343 self.assertEquals(channel.inBuffer, ['data']) | |
344 self.assertEquals(self.transport.packets, | |
345 [(connection.MSG_CHANNEL_WINDOW_ADJUST, '\x00\x00\x00\xff' | |
346 '\x00\x00\x00\x04')]) | |
347 self.transport.packets = [] | |
348 longData = 'a' * (channel.localWindowLeft + 1) | |
349 self.conn.ssh_CHANNEL_DATA('\x00\x00\x00\x00' + common.NS(longData)) | |
350 self.assertEquals(channel.inBuffer, ['data']) | |
351 self.assertEquals(self.transport.packets, | |
352 [(connection.MSG_CHANNEL_CLOSE, '\x00\x00\x00\xff')]) | |
353 channel = TestChannel() | |
354 self._openChannel(channel) | |
355 bigData = 'a' * (channel.localMaxPacket + 1) | |
356 self.transport.packets = [] | |
357 self.conn.ssh_CHANNEL_DATA('\x00\x00\x00\x01' + common.NS(bigData)) | |
358 self.assertEquals(channel.inBuffer, []) | |
359 self.assertEquals(self.transport.packets, | |
360 [(connection.MSG_CHANNEL_CLOSE, '\x00\x00\x00\xff')]) | |
361 | |
362 def test_CHANNEL_EXTENDED_DATA(self): | |
363 """ | |
364 Test that channel extended data messages are passed up to the channel, | |
365 or cause the channel to be closed if they're too big. | |
366 """ | |
367 channel = TestChannel(localWindow=6, localMaxPacket=5) | |
368 self._openChannel(channel) | |
369 self.conn.ssh_CHANNEL_EXTENDED_DATA('\x00\x00\x00\x00\x00\x00\x00' | |
370 '\x00' + common.NS('data')) | |
371 self.assertEquals(channel.extBuffer, [(0, 'data')]) | |
372 self.assertEquals(self.transport.packets, | |
373 [(connection.MSG_CHANNEL_WINDOW_ADJUST, '\x00\x00\x00\xff' | |
374 '\x00\x00\x00\x04')]) | |
375 self.transport.packets = [] | |
376 longData = 'a' * (channel.localWindowLeft + 1) | |
377 self.conn.ssh_CHANNEL_EXTENDED_DATA('\x00\x00\x00\x00\x00\x00\x00' | |
378 '\x00' + common.NS(longData)) | |
379 self.assertEquals(channel.extBuffer, [(0, 'data')]) | |
380 self.assertEquals(self.transport.packets, | |
381 [(connection.MSG_CHANNEL_CLOSE, '\x00\x00\x00\xff')]) | |
382 channel = TestChannel() | |
383 self._openChannel(channel) | |
384 bigData = 'a' * (channel.localMaxPacket + 1) | |
385 self.transport.packets = [] | |
386 self.conn.ssh_CHANNEL_EXTENDED_DATA('\x00\x00\x00\x01\x00\x00\x00' | |
387 '\x00' + common.NS(bigData)) | |
388 self.assertEquals(channel.extBuffer, []) | |
389 self.assertEquals(self.transport.packets, | |
390 [(connection.MSG_CHANNEL_CLOSE, '\x00\x00\x00\xff')]) | |
391 | |
392 def test_CHANNEL_EOF(self): | |
393 """ | |
394 Test that channel eof messages are passed up to the channel. | |
395 """ | |
396 channel = TestChannel() | |
397 self._openChannel(channel) | |
398 self.conn.ssh_CHANNEL_EOF('\x00\x00\x00\x00') | |
399 self.assertTrue(channel.gotEOF) | |
400 | |
401 def test_CHANNEL_CLOSE(self): | |
402 """ | |
403 Test that channel close messages are passed up to the channel. Also, | |
404 test that channel.close() is called if both sides are closed when this | |
405 message is received. | |
406 """ | |
407 channel = TestChannel() | |
408 self._openChannel(channel) | |
409 self.conn.sendClose(channel) | |
410 self.conn.ssh_CHANNEL_CLOSE('\x00\x00\x00\x00') | |
411 self.assertTrue(channel.gotOneClose) | |
412 self.assertTrue(channel.gotClosed) | |
413 | |
414 def test_CHANNEL_REQUEST_success(self): | |
415 """ | |
416 Test that channel requests that succeed send MSG_CHANNEL_SUCCESS. | |
417 """ | |
418 channel = TestChannel() | |
419 self._openChannel(channel) | |
420 self.conn.ssh_CHANNEL_REQUEST('\x00\x00\x00\x00' + common.NS('test') | |
421 + '\x00') | |
422 self.assertEquals(channel.numberRequests, 1) | |
423 d = self.conn.ssh_CHANNEL_REQUEST('\x00\x00\x00\x00' + common.NS( | |
424 'test') + '\xff' + 'data') | |
425 def check(result): | |
426 self.assertEquals(self.transport.packets, | |
427 [(connection.MSG_CHANNEL_SUCCESS, '\x00\x00\x00\xff')]) | |
428 d.addCallback(check) | |
429 return d | |
430 | |
431 def test_CHANNEL_REQUEST_failure(self): | |
432 """ | |
433 Test that channel requests that fail send MSG_CHANNEL_FAILURE. | |
434 """ | |
435 channel = TestChannel() | |
436 self._openChannel(channel) | |
437 d = self.conn.ssh_CHANNEL_REQUEST('\x00\x00\x00\x00' + common.NS( | |
438 'test') + '\xff') | |
439 def check(result): | |
440 self.assertEquals(self.transport.packets, | |
441 [(connection.MSG_CHANNEL_FAILURE, '\x00\x00\x00\xff' | |
442 )]) | |
443 d.addCallback(self.fail) | |
444 d.addErrback(check) | |
445 return d | |
446 | |
447 def test_CHANNEL_REQUEST_SUCCESS(self): | |
448 """ | |
449 Test that channel request success messages cause the Deferred to be | |
450 called back. | |
451 """ | |
452 channel = TestChannel() | |
453 self._openChannel(channel) | |
454 d = self.conn.sendRequest(channel, 'test', 'data', True) | |
455 self.conn.ssh_CHANNEL_SUCCESS('\x00\x00\x00\x00') | |
456 def check(result): | |
457 self.assertTrue(result) | |
458 return d | |
459 | |
460 def test_CHANNEL_REQUEST_FAILURE(self): | |
461 """ | |
462 Test that channel request failure messages cause the Deferred to be | |
463 erred back. | |
464 """ | |
465 channel = TestChannel() | |
466 self._openChannel(channel) | |
467 d = self.conn.sendRequest(channel, 'test', '', True) | |
468 self.conn.ssh_CHANNEL_FAILURE('\x00\x00\x00\x00') | |
469 def check(result): | |
470 self.assertEquals(result.value.value, 'channel request failed') | |
471 d.addCallback(self.fail) | |
472 d.addErrback(check) | |
473 return d | |
474 | |
475 def test_sendGlobalRequest(self): | |
476 """ | |
477 Test that global request messages are sent in the right format. | |
478 """ | |
479 d = self.conn.sendGlobalRequest('wantReply', 'data', True) | |
480 self.conn.sendGlobalRequest('noReply', '', False) | |
481 self.assertEquals(self.transport.packets, | |
482 [(connection.MSG_GLOBAL_REQUEST, common.NS('wantReply') + | |
483 '\xffdata'), | |
484 (connection.MSG_GLOBAL_REQUEST, common.NS('noReply') + | |
485 '\x00')]) | |
486 self.assertEquals(self.conn.deferreds, {'global':[d]}) | |
487 | |
488 def test_openChannel(self): | |
489 """ | |
490 Test that open channel messages are sent in the right format. | |
491 """ | |
492 channel = TestChannel() | |
493 self.conn.openChannel(channel, 'aaaa') | |
494 self.assertEquals(self.transport.packets, | |
495 [(connection.MSG_CHANNEL_OPEN, common.NS('TestChannel') + | |
496 '\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x80\x00aaaa')]) | |
497 self.assertEquals(channel.id, 0) | |
498 self.assertEquals(self.conn.localChannelID, 1) | |
499 | |
500 def test_sendRequest(self): | |
501 """ | |
502 Test that channel request messages are sent in the right format. | |
503 """ | |
504 channel = TestChannel() | |
505 self._openChannel(channel) | |
506 d = self.conn.sendRequest(channel, 'test', 'test', True) | |
507 self.conn.sendRequest(channel, 'test2', '', False) | |
508 channel.localClosed = True # emulate sending a close message | |
509 self.conn.sendRequest(channel, 'test3', '', True) | |
510 self.assertEquals(self.transport.packets, | |
511 [(connection.MSG_CHANNEL_REQUEST, '\x00\x00\x00\xff' + | |
512 common.NS('test') + '\x01test'), | |
513 (connection.MSG_CHANNEL_REQUEST, '\x00\x00\x00\xff' + | |
514 common.NS('test2') + '\x00')]) | |
515 self.assertEquals(self.conn.deferreds, {0:[d]}) | |
516 | |
517 def test_adjustWindow(self): | |
518 """ | |
519 Test that channel window adjust messages cause bytes to be added | |
520 to the window. | |
521 """ | |
522 channel = TestChannel(localWindow=5) | |
523 self._openChannel(channel) | |
524 channel.localWindowLeft = 0 | |
525 self.conn.adjustWindow(channel, 1) | |
526 self.assertEquals(channel.localWindowLeft, 1) | |
527 channel.localClosed = True | |
528 self.conn.adjustWindow(channel, 2) | |
529 self.assertEquals(channel.localWindowLeft, 1) | |
530 self.assertEquals(self.transport.packets, | |
531 [(connection.MSG_CHANNEL_WINDOW_ADJUST, '\x00\x00\x00\xff' | |
532 '\x00\x00\x00\x01')]) | |
533 | |
534 def test_sendData(self): | |
535 """ | |
536 Test that channel data messages are sent in the right format. | |
537 """ | |
538 channel = TestChannel() | |
539 self._openChannel(channel) | |
540 self.conn.sendData(channel, 'a') | |
541 channel.localClosed = True | |
542 self.conn.sendData(channel, 'b') | |
543 self.assertEquals(self.transport.packets, | |
544 [(connection.MSG_CHANNEL_DATA, '\x00\x00\x00\xff' + | |
545 common.NS('a'))]) | |
546 | |
547 def test_sendExtendedData(self): | |
548 """ | |
549 Test that channel extended data messages are sent in the right format. | |
550 """ | |
551 channel = TestChannel() | |
552 self._openChannel(channel) | |
553 self.conn.sendExtendedData(channel, 1, 'test') | |
554 channel.localClosed = True | |
555 self.conn.sendExtendedData(channel, 2, 'test2') | |
556 self.assertEquals(self.transport.packets, | |
557 [(connection.MSG_CHANNEL_EXTENDED_DATA, '\x00\x00\x00\xff' + | |
558 '\x00\x00\x00\x01' + common.NS('test'))]) | |
559 | |
560 def test_sendEOF(self): | |
561 """ | |
562 Test that channel EOF messages are sent in the right format. | |
563 """ | |
564 channel = TestChannel() | |
565 self._openChannel(channel) | |
566 self.conn.sendEOF(channel) | |
567 self.assertEquals(self.transport.packets, | |
568 [(connection.MSG_CHANNEL_EOF, '\x00\x00\x00\xff')]) | |
569 channel.localClosed = True | |
570 self.conn.sendEOF(channel) | |
571 self.assertEquals(self.transport.packets, | |
572 [(connection.MSG_CHANNEL_EOF, '\x00\x00\x00\xff')]) | |
573 | |
574 def test_sendClose(self): | |
575 """ | |
576 Test that channel close messages are sent in the right format. | |
577 """ | |
578 channel = TestChannel() | |
579 self._openChannel(channel) | |
580 self.conn.sendClose(channel) | |
581 self.assertTrue(channel.localClosed) | |
582 self.assertEquals(self.transport.packets, | |
583 [(connection.MSG_CHANNEL_CLOSE, '\x00\x00\x00\xff')]) | |
584 self.conn.sendClose(channel) | |
585 self.assertEquals(self.transport.packets, | |
586 [(connection.MSG_CHANNEL_CLOSE, '\x00\x00\x00\xff')]) | |
587 | |
588 channel2 = TestChannel() | |
589 self._openChannel(channel2) | |
590 channel2.remoteClosed = True | |
591 self.conn.sendClose(channel2) | |
592 self.assertTrue(channel2.gotClosed) | |
593 | |
594 def test_getChannelWithAvatar(self): | |
595 """ | |
596 Test that getChannel dispatches to the avatar when an avatar is | |
597 present. Correct functioning without the avatar is verified in | |
598 test_CHANNEL_OPEN. | |
599 """ | |
600 channel = self.conn.getChannel('TestChannel', 50, 30, 'data') | |
601 self.assertEquals(channel.data, 'data') | |
602 self.assertEquals(channel.remoteWindowLeft, 50) | |
603 self.assertEquals(channel.remoteMaxPacket, 30) | |
604 self.assertRaises(error.ConchError, self.conn.getChannel, | |
605 'BadChannel', 50, 30, 'data') | |
606 | |
607 def test_gotGlobalRequestWithoutAvatar(self): | |
608 """ | |
609 Test that gotGlobalRequests dispatches to global_* without an avatar. | |
610 """ | |
611 del self.transport.avatar | |
612 self.assertTrue(self.conn.gotGlobalRequest('TestGlobal', 'data')) | |
613 self.assertEquals(self.conn.gotGlobalRequest('Test-Data', 'data'), | |
614 (True, 'data')) | |
615 self.assertFalse(self.conn.gotGlobalRequest('BadGlobal', 'data')) | |
OLD | NEW |