Mini Shell
# Copyright (c) 2007-2010 Twisted Matrix Laboratories.
# See LICENSE for details
"""
This module tests twisted.conch.ssh.connection.
"""
import struct
from twisted.conch.ssh import channel
from twisted.conch.test import test_userauth
from twisted.python.reflect import requireModule
from twisted.trial import unittest
cryptography = requireModule("cryptography")
from twisted.conch import error
if cryptography:
from twisted.conch.ssh import common, connection
else:
class connection: # type: ignore[no-redef]
class SSHConnection:
pass
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
gotClosed = 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}
"""
if not cryptography:
skip = "Cannot run without cryptography"
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 not cryptography:
skip = "Cannot run without cryptography"
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(channel1.gotClosed)
self.assertFalse(channel2.gotOpen)
self.assertFalse(channel2.gotClosed)
self.conn.serviceStopped()
self.assertTrue(channel1.gotClosed)
self.assertFalse(channel2.gotOpen)
self.assertFalse(channel2.gotClosed)
from twisted.internet.error import ConnectionLost
self.assertIsInstance(channel2.openFailureReason, ConnectionLost)
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, f"Expected one error, got: {errors!r}")
self.assertEqual(errors[0].value.args, (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_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.assertTrue(channel.gotOpen)
self.assertFalse(channel.gotOneClose)
self.assertFalse(channel.gotClosed)
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)
self.assertTrue(channel2.gotOpen)
self.assertFalse(channel2.gotClosed)
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 not cryptography:
skip = "Cannot run without cryptography"
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
Zerion Mini Shell 1.0