123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730 |
- # Copyright (c) 2007-2010 Twisted Matrix Laboratories.
- # See LICENSE for details
- """
- This module tests twisted.conch.ssh.connection.
- """
- from __future__ import division, absolute_import
- import struct
- from twisted.conch import error
- from twisted.conch.ssh import channel, common, connection
- from twisted.python.compat import long
- from twisted.trial import unittest
- from twisted.conch.test import test_userauth
- class TestChannel(channel.SSHChannel):
- """
- A mocked-up version of twisted.conch.ssh.channel.SSHChannel.
- @ivar gotOpen: True if channelOpen has been called.
- @type gotOpen: L{bool}
- @ivar specificData: the specific channel open data passed to channelOpen.
- @type specificData: L{bytes}
- @ivar openFailureReason: the reason passed to openFailed.
- @type openFailed: C{error.ConchError}
- @ivar inBuffer: a C{list} of strings received by the channel.
- @type inBuffer: C{list}
- @ivar extBuffer: a C{list} of 2-tuples (type, extended data) of received by
- the channel.
- @type extBuffer: C{list}
- @ivar numberRequests: the number of requests that have been made to this
- channel.
- @type numberRequests: L{int}
- @ivar gotEOF: True if the other side sent EOF.
- @type gotEOF: L{bool}
- @ivar gotOneClose: True if the other side closed the connection.
- @type gotOneClose: L{bool}
- @ivar gotClosed: True if the channel is closed.
- @type gotClosed: L{bool}
- """
- name = b"TestChannel"
- gotOpen = False
- def logPrefix(self):
- return "TestChannel %i" % self.id
- def channelOpen(self, specificData):
- """
- The channel is open. Set up the instance variables.
- """
- self.gotOpen = True
- self.specificData = specificData
- self.inBuffer = []
- self.extBuffer = []
- self.numberRequests = 0
- self.gotEOF = False
- self.gotOneClose = False
- self.gotClosed = False
- def openFailed(self, reason):
- """
- Opening the channel failed. Store the reason why.
- """
- self.openFailureReason = reason
- def request_test(self, data):
- """
- A test request. Return True if data is 'data'.
- @type data: L{bytes}
- """
- self.numberRequests += 1
- return data == b'data'
- def dataReceived(self, data):
- """
- Data was received. Store it in the buffer.
- """
- self.inBuffer.append(data)
- def extReceived(self, code, data):
- """
- Extended data was received. Store it in the buffer.
- """
- self.extBuffer.append((code, data))
- def eofReceived(self):
- """
- EOF was received. Remember it.
- """
- self.gotEOF = True
- def closeReceived(self):
- """
- Close was received. Remember it.
- """
- self.gotOneClose = True
- def closed(self):
- """
- The channel is closed. Rembember it.
- """
- self.gotClosed = True
- class TestAvatar:
- """
- A mocked-up version of twisted.conch.avatar.ConchUser
- """
- _ARGS_ERROR_CODE = 123
- def lookupChannel(self, channelType, windowSize, maxPacket, data):
- """
- The server wants us to return a channel. If the requested channel is
- our TestChannel, return it, otherwise return None.
- """
- if channelType == TestChannel.name:
- return TestChannel(remoteWindow=windowSize,
- remoteMaxPacket=maxPacket,
- data=data, avatar=self)
- elif channelType == b"conch-error-args":
- # Raise a ConchError with backwards arguments to make sure the
- # connection fixes it for us. This case should be deprecated and
- # deleted eventually, but only after all of Conch gets the argument
- # order right.
- raise error.ConchError(
- self._ARGS_ERROR_CODE, "error args in wrong order")
- def gotGlobalRequest(self, requestType, data):
- """
- The client has made a global request. If the global request is
- 'TestGlobal', return True. If the global request is 'TestData',
- return True and the request-specific data we received. Otherwise,
- return False.
- """
- if requestType == b'TestGlobal':
- return True
- elif requestType == b'TestData':
- return True, data
- else:
- return False
- class TestConnection(connection.SSHConnection):
- """
- A subclass of SSHConnection for testing.
- @ivar channel: the current channel.
- @type channel. C{TestChannel}
- """
- def logPrefix(self):
- return "TestConnection"
- def global_TestGlobal(self, data):
- """
- The other side made the 'TestGlobal' global request. Return True.
- """
- return True
- def global_Test_Data(self, data):
- """
- The other side made the 'Test-Data' global request. Return True and
- the data we received.
- """
- return True, data
- def channel_TestChannel(self, windowSize, maxPacket, data):
- """
- The other side is requesting the TestChannel. Create a C{TestChannel}
- instance, store it, and return it.
- """
- self.channel = TestChannel(remoteWindow=windowSize,
- remoteMaxPacket=maxPacket, data=data)
- return self.channel
- def channel_ErrorChannel(self, windowSize, maxPacket, data):
- """
- The other side is requesting the ErrorChannel. Raise an exception.
- """
- raise AssertionError('no such thing')
- class ConnectionTests(unittest.TestCase):
- if test_userauth.transport is None:
- skip = "Cannot run without both cryptography and pyasn1"
- def setUp(self):
- self.transport = test_userauth.FakeTransport(None)
- self.transport.avatar = TestAvatar()
- self.conn = TestConnection()
- self.conn.transport = self.transport
- self.conn.serviceStarted()
- def _openChannel(self, channel):
- """
- Open the channel with the default connection.
- """
- self.conn.openChannel(channel)
- self.transport.packets = self.transport.packets[:-1]
- self.conn.ssh_CHANNEL_OPEN_CONFIRMATION(struct.pack('>2L',
- channel.id, 255) + b'\x00\x02\x00\x00\x00\x00\x80\x00')
- def tearDown(self):
- self.conn.serviceStopped()
- def test_linkAvatar(self):
- """
- Test that the connection links itself to the avatar in the
- transport.
- """
- self.assertIs(self.transport.avatar.conn, self.conn)
- def test_serviceStopped(self):
- """
- Test that serviceStopped() closes any open channels.
- """
- channel1 = TestChannel()
- channel2 = TestChannel()
- self.conn.openChannel(channel1)
- self.conn.openChannel(channel2)
- self.conn.ssh_CHANNEL_OPEN_CONFIRMATION(b'\x00\x00\x00\x00' * 4)
- self.assertTrue(channel1.gotOpen)
- self.assertFalse(channel2.gotOpen)
- self.conn.serviceStopped()
- self.assertTrue(channel1.gotClosed)
- def test_GLOBAL_REQUEST(self):
- """
- Test that global request packets are dispatched to the global_*
- methods and the return values are translated into success or failure
- messages.
- """
- self.conn.ssh_GLOBAL_REQUEST(common.NS(b'TestGlobal') + b'\xff')
- self.assertEqual(self.transport.packets,
- [(connection.MSG_REQUEST_SUCCESS, b'')])
- self.transport.packets = []
- self.conn.ssh_GLOBAL_REQUEST(common.NS(b'TestData') + b'\xff' +
- b'test data')
- self.assertEqual(self.transport.packets,
- [(connection.MSG_REQUEST_SUCCESS, b'test data')])
- self.transport.packets = []
- self.conn.ssh_GLOBAL_REQUEST(common.NS(b'TestBad') + b'\xff')
- self.assertEqual(self.transport.packets,
- [(connection.MSG_REQUEST_FAILURE, b'')])
- self.transport.packets = []
- self.conn.ssh_GLOBAL_REQUEST(common.NS(b'TestGlobal') + b'\x00')
- self.assertEqual(self.transport.packets, [])
- def test_REQUEST_SUCCESS(self):
- """
- Test that global request success packets cause the Deferred to be
- called back.
- """
- d = self.conn.sendGlobalRequest(b'request', b'data', True)
- self.conn.ssh_REQUEST_SUCCESS(b'data')
- def check(data):
- self.assertEqual(data, b'data')
- d.addCallback(check)
- d.addErrback(self.fail)
- return d
- def test_REQUEST_FAILURE(self):
- """
- Test that global request failure packets cause the Deferred to be
- erred back.
- """
- d = self.conn.sendGlobalRequest(b'request', b'data', True)
- self.conn.ssh_REQUEST_FAILURE(b'data')
- def check(f):
- self.assertEqual(f.value.data, b'data')
- d.addCallback(self.fail)
- d.addErrback(check)
- return d
- def test_CHANNEL_OPEN(self):
- """
- Test that open channel packets cause a channel to be created and
- opened or a failure message to be returned.
- """
- del self.transport.avatar
- self.conn.ssh_CHANNEL_OPEN(common.NS(b'TestChannel') +
- b'\x00\x00\x00\x01' * 4)
- self.assertTrue(self.conn.channel.gotOpen)
- self.assertEqual(self.conn.channel.conn, self.conn)
- self.assertEqual(self.conn.channel.data, b'\x00\x00\x00\x01')
- self.assertEqual(self.conn.channel.specificData, b'\x00\x00\x00\x01')
- self.assertEqual(self.conn.channel.remoteWindowLeft, 1)
- self.assertEqual(self.conn.channel.remoteMaxPacket, 1)
- self.assertEqual(self.transport.packets,
- [(connection.MSG_CHANNEL_OPEN_CONFIRMATION,
- b'\x00\x00\x00\x01\x00\x00\x00\x00\x00\x02\x00\x00'
- b'\x00\x00\x80\x00')])
- self.transport.packets = []
- self.conn.ssh_CHANNEL_OPEN(common.NS(b'BadChannel') +
- b'\x00\x00\x00\x02' * 4)
- self.flushLoggedErrors()
- self.assertEqual(self.transport.packets,
- [(connection.MSG_CHANNEL_OPEN_FAILURE,
- b'\x00\x00\x00\x02\x00\x00\x00\x03' + common.NS(
- b'unknown channel') + common.NS(b''))])
- self.transport.packets = []
- self.conn.ssh_CHANNEL_OPEN(common.NS(b'ErrorChannel') +
- b'\x00\x00\x00\x02' * 4)
- self.flushLoggedErrors()
- self.assertEqual(self.transport.packets,
- [(connection.MSG_CHANNEL_OPEN_FAILURE,
- b'\x00\x00\x00\x02\x00\x00\x00\x02' + common.NS(
- b'unknown failure') + common.NS(b''))])
- def _lookupChannelErrorTest(self, code):
- """
- Deliver a request for a channel open which will result in an exception
- being raised during channel lookup. Assert that an error response is
- delivered as a result.
- """
- self.transport.avatar._ARGS_ERROR_CODE = code
- self.conn.ssh_CHANNEL_OPEN(
- common.NS(b'conch-error-args') + b'\x00\x00\x00\x01' * 4)
- errors = self.flushLoggedErrors(error.ConchError)
- self.assertEqual(
- len(errors), 1, "Expected one error, got: %r" % (errors,))
- self.assertEqual(errors[0].value.args, (long(123), "error args in wrong order"))
- self.assertEqual(
- self.transport.packets,
- [(connection.MSG_CHANNEL_OPEN_FAILURE,
- # The response includes some bytes which identifying the
- # associated request, as well as the error code (7b in hex) and
- # the error message.
- b'\x00\x00\x00\x01\x00\x00\x00\x7b' + common.NS(
- b'error args in wrong order') + common.NS(b''))])
- def test_lookupChannelError(self):
- """
- If a C{lookupChannel} implementation raises L{error.ConchError} with the
- arguments in the wrong order, a C{MSG_CHANNEL_OPEN} failure is still
- sent in response to the message.
- This is a temporary work-around until L{error.ConchError} is given
- better attributes and all of the Conch code starts constructing
- instances of it properly. Eventually this functionality should be
- deprecated and then removed.
- """
- self._lookupChannelErrorTest(123)
- def test_lookupChannelErrorLongCode(self):
- """
- Like L{test_lookupChannelError}, but for the case where the failure code
- is represented as a L{long} instead of a L{int}.
- """
- self._lookupChannelErrorTest(long(123))
- def test_CHANNEL_OPEN_CONFIRMATION(self):
- """
- Test that channel open confirmation packets cause the channel to be
- notified that it's open.
- """
- channel = TestChannel()
- self.conn.openChannel(channel)
- self.conn.ssh_CHANNEL_OPEN_CONFIRMATION(b'\x00\x00\x00\x00'*5)
- self.assertEqual(channel.remoteWindowLeft, 0)
- self.assertEqual(channel.remoteMaxPacket, 0)
- self.assertEqual(channel.specificData, b'\x00\x00\x00\x00')
- self.assertEqual(self.conn.channelsToRemoteChannel[channel],
- 0)
- self.assertEqual(self.conn.localToRemoteChannel[0], 0)
- def test_CHANNEL_OPEN_FAILURE(self):
- """
- Test that channel open failure packets cause the channel to be
- notified that its opening failed.
- """
- channel = TestChannel()
- self.conn.openChannel(channel)
- self.conn.ssh_CHANNEL_OPEN_FAILURE(b'\x00\x00\x00\x00\x00\x00\x00'
- b'\x01' + common.NS(b'failure!'))
- self.assertEqual(channel.openFailureReason.args, (b'failure!', 1))
- self.assertIsNone(self.conn.channels.get(channel))
- def test_CHANNEL_WINDOW_ADJUST(self):
- """
- Test that channel window adjust messages add bytes to the channel
- window.
- """
- channel = TestChannel()
- self._openChannel(channel)
- oldWindowSize = channel.remoteWindowLeft
- self.conn.ssh_CHANNEL_WINDOW_ADJUST(b'\x00\x00\x00\x00\x00\x00\x00'
- b'\x01')
- self.assertEqual(channel.remoteWindowLeft, oldWindowSize + 1)
- def test_CHANNEL_DATA(self):
- """
- Test that channel data messages are passed up to the channel, or
- cause the channel to be closed if the data is too large.
- """
- channel = TestChannel(localWindow=6, localMaxPacket=5)
- self._openChannel(channel)
- self.conn.ssh_CHANNEL_DATA(b'\x00\x00\x00\x00' + common.NS(b'data'))
- self.assertEqual(channel.inBuffer, [b'data'])
- self.assertEqual(self.transport.packets,
- [(connection.MSG_CHANNEL_WINDOW_ADJUST, b'\x00\x00\x00\xff'
- b'\x00\x00\x00\x04')])
- self.transport.packets = []
- longData = b'a' * (channel.localWindowLeft + 1)
- self.conn.ssh_CHANNEL_DATA(b'\x00\x00\x00\x00' + common.NS(longData))
- self.assertEqual(channel.inBuffer, [b'data'])
- self.assertEqual(self.transport.packets,
- [(connection.MSG_CHANNEL_CLOSE, b'\x00\x00\x00\xff')])
- channel = TestChannel()
- self._openChannel(channel)
- bigData = b'a' * (channel.localMaxPacket + 1)
- self.transport.packets = []
- self.conn.ssh_CHANNEL_DATA(b'\x00\x00\x00\x01' + common.NS(bigData))
- self.assertEqual(channel.inBuffer, [])
- self.assertEqual(self.transport.packets,
- [(connection.MSG_CHANNEL_CLOSE, b'\x00\x00\x00\xff')])
- def test_CHANNEL_EXTENDED_DATA(self):
- """
- Test that channel extended data messages are passed up to the channel,
- or cause the channel to be closed if they're too big.
- """
- channel = TestChannel(localWindow=6, localMaxPacket=5)
- self._openChannel(channel)
- self.conn.ssh_CHANNEL_EXTENDED_DATA(b'\x00\x00\x00\x00\x00\x00\x00'
- b'\x00' + common.NS(b'data'))
- self.assertEqual(channel.extBuffer, [(0, b'data')])
- self.assertEqual(self.transport.packets,
- [(connection.MSG_CHANNEL_WINDOW_ADJUST, b'\x00\x00\x00\xff'
- b'\x00\x00\x00\x04')])
- self.transport.packets = []
- longData = b'a' * (channel.localWindowLeft + 1)
- self.conn.ssh_CHANNEL_EXTENDED_DATA(b'\x00\x00\x00\x00\x00\x00\x00'
- b'\x00' + common.NS(longData))
- self.assertEqual(channel.extBuffer, [(0, b'data')])
- self.assertEqual(self.transport.packets,
- [(connection.MSG_CHANNEL_CLOSE, b'\x00\x00\x00\xff')])
- channel = TestChannel()
- self._openChannel(channel)
- bigData = b'a' * (channel.localMaxPacket + 1)
- self.transport.packets = []
- self.conn.ssh_CHANNEL_EXTENDED_DATA(b'\x00\x00\x00\x01\x00\x00\x00'
- b'\x00' + common.NS(bigData))
- self.assertEqual(channel.extBuffer, [])
- self.assertEqual(self.transport.packets,
- [(connection.MSG_CHANNEL_CLOSE, b'\x00\x00\x00\xff')])
- def test_CHANNEL_EOF(self):
- """
- Test that channel eof messages are passed up to the channel.
- """
- channel = TestChannel()
- self._openChannel(channel)
- self.conn.ssh_CHANNEL_EOF(b'\x00\x00\x00\x00')
- self.assertTrue(channel.gotEOF)
- def test_CHANNEL_CLOSE(self):
- """
- Test that channel close messages are passed up to the channel. Also,
- test that channel.close() is called if both sides are closed when this
- message is received.
- """
- channel = TestChannel()
- self._openChannel(channel)
- self.conn.sendClose(channel)
- self.conn.ssh_CHANNEL_CLOSE(b'\x00\x00\x00\x00')
- self.assertTrue(channel.gotOneClose)
- self.assertTrue(channel.gotClosed)
- def test_CHANNEL_REQUEST_success(self):
- """
- Test that channel requests that succeed send MSG_CHANNEL_SUCCESS.
- """
- channel = TestChannel()
- self._openChannel(channel)
- self.conn.ssh_CHANNEL_REQUEST(b'\x00\x00\x00\x00' + common.NS(b'test')
- + b'\x00')
- self.assertEqual(channel.numberRequests, 1)
- d = self.conn.ssh_CHANNEL_REQUEST(b'\x00\x00\x00\x00' + common.NS(
- b'test') + b'\xff' + b'data')
- def check(result):
- self.assertEqual(self.transport.packets,
- [(connection.MSG_CHANNEL_SUCCESS, b'\x00\x00\x00\xff')])
- d.addCallback(check)
- return d
- def test_CHANNEL_REQUEST_failure(self):
- """
- Test that channel requests that fail send MSG_CHANNEL_FAILURE.
- """
- channel = TestChannel()
- self._openChannel(channel)
- d = self.conn.ssh_CHANNEL_REQUEST(b'\x00\x00\x00\x00' + common.NS(
- b'test') + b'\xff')
- def check(result):
- self.assertEqual(self.transport.packets,
- [(connection.MSG_CHANNEL_FAILURE, b'\x00\x00\x00\xff'
- )])
- d.addCallback(self.fail)
- d.addErrback(check)
- return d
- def test_CHANNEL_REQUEST_SUCCESS(self):
- """
- Test that channel request success messages cause the Deferred to be
- called back.
- """
- channel = TestChannel()
- self._openChannel(channel)
- d = self.conn.sendRequest(channel, b'test', b'data', True)
- self.conn.ssh_CHANNEL_SUCCESS(b'\x00\x00\x00\x00')
- def check(result):
- self.assertTrue(result)
- return d
- def test_CHANNEL_REQUEST_FAILURE(self):
- """
- Test that channel request failure messages cause the Deferred to be
- erred back.
- """
- channel = TestChannel()
- self._openChannel(channel)
- d = self.conn.sendRequest(channel, b'test', b'', True)
- self.conn.ssh_CHANNEL_FAILURE(b'\x00\x00\x00\x00')
- def check(result):
- self.assertEqual(result.value.value, 'channel request failed')
- d.addCallback(self.fail)
- d.addErrback(check)
- return d
- def test_sendGlobalRequest(self):
- """
- Test that global request messages are sent in the right format.
- """
- d = self.conn.sendGlobalRequest(b'wantReply', b'data', True)
- # must be added to prevent errbacking during teardown
- d.addErrback(lambda failure: None)
- self.conn.sendGlobalRequest(b'noReply', b'', False)
- self.assertEqual(self.transport.packets,
- [(connection.MSG_GLOBAL_REQUEST, common.NS(b'wantReply') +
- b'\xffdata'),
- (connection.MSG_GLOBAL_REQUEST, common.NS(b'noReply') +
- b'\x00')])
- self.assertEqual(self.conn.deferreds, {'global':[d]})
- def test_openChannel(self):
- """
- Test that open channel messages are sent in the right format.
- """
- channel = TestChannel()
- self.conn.openChannel(channel, b'aaaa')
- self.assertEqual(self.transport.packets,
- [(connection.MSG_CHANNEL_OPEN, common.NS(b'TestChannel') +
- b'\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x80\x00aaaa')])
- self.assertEqual(channel.id, 0)
- self.assertEqual(self.conn.localChannelID, 1)
- def test_sendRequest(self):
- """
- Test that channel request messages are sent in the right format.
- """
- channel = TestChannel()
- self._openChannel(channel)
- d = self.conn.sendRequest(channel, b'test', b'test', True)
- # needed to prevent errbacks during teardown.
- d.addErrback(lambda failure: None)
- self.conn.sendRequest(channel, b'test2', b'', False)
- channel.localClosed = True # emulate sending a close message
- self.conn.sendRequest(channel, b'test3', b'', True)
- self.assertEqual(self.transport.packets,
- [(connection.MSG_CHANNEL_REQUEST, b'\x00\x00\x00\xff' +
- common.NS(b'test') + b'\x01test'),
- (connection.MSG_CHANNEL_REQUEST, b'\x00\x00\x00\xff' +
- common.NS(b'test2') + b'\x00')])
- self.assertEqual(self.conn.deferreds[0], [d])
- def test_adjustWindow(self):
- """
- Test that channel window adjust messages cause bytes to be added
- to the window.
- """
- channel = TestChannel(localWindow=5)
- self._openChannel(channel)
- channel.localWindowLeft = 0
- self.conn.adjustWindow(channel, 1)
- self.assertEqual(channel.localWindowLeft, 1)
- channel.localClosed = True
- self.conn.adjustWindow(channel, 2)
- self.assertEqual(channel.localWindowLeft, 1)
- self.assertEqual(self.transport.packets,
- [(connection.MSG_CHANNEL_WINDOW_ADJUST, b'\x00\x00\x00\xff'
- b'\x00\x00\x00\x01')])
- def test_sendData(self):
- """
- Test that channel data messages are sent in the right format.
- """
- channel = TestChannel()
- self._openChannel(channel)
- self.conn.sendData(channel, b'a')
- channel.localClosed = True
- self.conn.sendData(channel, b'b')
- self.assertEqual(self.transport.packets,
- [(connection.MSG_CHANNEL_DATA, b'\x00\x00\x00\xff' +
- common.NS(b'a'))])
- def test_sendExtendedData(self):
- """
- Test that channel extended data messages are sent in the right format.
- """
- channel = TestChannel()
- self._openChannel(channel)
- self.conn.sendExtendedData(channel, 1, b'test')
- channel.localClosed = True
- self.conn.sendExtendedData(channel, 2, b'test2')
- self.assertEqual(self.transport.packets,
- [(connection.MSG_CHANNEL_EXTENDED_DATA, b'\x00\x00\x00\xff' +
- b'\x00\x00\x00\x01' + common.NS(b'test'))])
- def test_sendEOF(self):
- """
- Test that channel EOF messages are sent in the right format.
- """
- channel = TestChannel()
- self._openChannel(channel)
- self.conn.sendEOF(channel)
- self.assertEqual(self.transport.packets,
- [(connection.MSG_CHANNEL_EOF, b'\x00\x00\x00\xff')])
- channel.localClosed = True
- self.conn.sendEOF(channel)
- self.assertEqual(self.transport.packets,
- [(connection.MSG_CHANNEL_EOF, b'\x00\x00\x00\xff')])
- def test_sendClose(self):
- """
- Test that channel close messages are sent in the right format.
- """
- channel = TestChannel()
- self._openChannel(channel)
- self.conn.sendClose(channel)
- self.assertTrue(channel.localClosed)
- self.assertEqual(self.transport.packets,
- [(connection.MSG_CHANNEL_CLOSE, b'\x00\x00\x00\xff')])
- self.conn.sendClose(channel)
- self.assertEqual(self.transport.packets,
- [(connection.MSG_CHANNEL_CLOSE, b'\x00\x00\x00\xff')])
- channel2 = TestChannel()
- self._openChannel(channel2)
- channel2.remoteClosed = True
- self.conn.sendClose(channel2)
- self.assertTrue(channel2.gotClosed)
- def test_getChannelWithAvatar(self):
- """
- Test that getChannel dispatches to the avatar when an avatar is
- present. Correct functioning without the avatar is verified in
- test_CHANNEL_OPEN.
- """
- channel = self.conn.getChannel(b'TestChannel', 50, 30, b'data')
- self.assertEqual(channel.data, b'data')
- self.assertEqual(channel.remoteWindowLeft, 50)
- self.assertEqual(channel.remoteMaxPacket, 30)
- self.assertRaises(error.ConchError, self.conn.getChannel,
- b'BadChannel', 50, 30, b'data')
- def test_gotGlobalRequestWithoutAvatar(self):
- """
- Test that gotGlobalRequests dispatches to global_* without an avatar.
- """
- del self.transport.avatar
- self.assertTrue(self.conn.gotGlobalRequest(b'TestGlobal', b'data'))
- self.assertEqual(self.conn.gotGlobalRequest(b'Test-Data', b'data'),
- (True, b'data'))
- self.assertFalse(self.conn.gotGlobalRequest(b'BadGlobal', b'data'))
- def test_channelClosedCausesLeftoverChannelDeferredsToErrback(self):
- """
- Whenever an SSH channel gets closed any Deferred that was returned by a
- sendRequest() on its parent connection must be errbacked.
- """
- channel = TestChannel()
- self._openChannel(channel)
- d = self.conn.sendRequest(
- channel, b"dummyrequest", b"dummydata", wantReply=1)
- d = self.assertFailure(d, error.ConchError)
- self.conn.channelClosed(channel)
- return d
- class CleanConnectionShutdownTests(unittest.TestCase):
- """
- Check whether correct cleanup is performed on connection shutdown.
- """
- if test_userauth.transport is None:
- skip = "Cannot run without both cryptography and pyasn1"
- def setUp(self):
- self.transport = test_userauth.FakeTransport(None)
- self.transport.avatar = TestAvatar()
- self.conn = TestConnection()
- self.conn.transport = self.transport
- def test_serviceStoppedCausesLeftoverGlobalDeferredsToErrback(self):
- """
- Once the service is stopped any leftover global deferred returned by
- a sendGlobalRequest() call must be errbacked.
- """
- self.conn.serviceStarted()
- d = self.conn.sendGlobalRequest(
- b"dummyrequest", b"dummydata", wantReply=1)
- d = self.assertFailure(d, error.ConchError)
- self.conn.serviceStopped()
- return d
|