Skip to content

Commit 7691cb0

Browse files
committed
Avoid leaking event subscriptions when an exception is thrown during initialization of ShellStream.
Handle error situations when initializing ShellStream.
1 parent 69882b3 commit 7691cb0

9 files changed

+682
-19
lines changed

src/Renci.SshNet.Tests.NET35/Renci.SshNet.Tests.NET35.csproj

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@
105105
<Compile Include="..\Renci.SshNet.Tests\Classes\Channels\ChannelForwardedTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs">
106106
<Link>Classes\Channels\ChannelForwardedTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs</Link>
107107
</Compile>
108+
<Compile Include="..\Renci.SshNet.Tests\Classes\Channels\ChannelSessionTestBase.cs">
109+
<Link>Classes\Channels\ChannelSessionTestBase.cs</Link>
110+
</Compile>
108111
<Compile Include="..\Renci.SshNet.Tests\Classes\Channels\ChannelSessionTest_Disposed_Closed.cs">
109112
<Link>Classes\Channels\ChannelSessionTest_Disposed_Closed.cs</Link>
110113
</Compile>
@@ -159,6 +162,9 @@
159162
<Compile Include="..\Renci.SshNet.Tests\Classes\Channels\ChannelStub.cs">
160163
<Link>Classes\Channels\ChannelStub.cs</Link>
161164
</Compile>
165+
<Compile Include="..\Renci.SshNet.Tests\Classes\Channels\ChannelTestBase.cs">
166+
<Link>Classes\Channels\ChannelTestBase.cs</Link>
167+
</Compile>
162168
<Compile Include="..\Renci.SshNet.Tests\Classes\Channels\ChannelTest_Dispose_SessionIsConnectedAndChannelIsNotOpen.cs">
163169
<Link>Classes\Channels\ChannelTest_Dispose_SessionIsConnectedAndChannelIsNotOpen.cs</Link>
164170
</Compile>
@@ -171,6 +177,12 @@
171177
<Compile Include="..\Renci.SshNet.Tests\Classes\Channels\ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived.cs">
172178
<Link>Classes\Channels\ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived.cs</Link>
173179
</Compile>
180+
<Compile Include="..\Renci.SshNet.Tests\Classes\Channels\ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived_DisconnectWaitingForChannelCloseMessage.cs">
181+
<Link>Classes\Channels\ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived_DisconnectWaitingForChannelCloseMessage.cs</Link>
182+
</Compile>
183+
<Compile Include="..\Renci.SshNet.Tests\Classes\Channels\ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived_TimeoutWaitingForChannelCloseMessage.cs">
184+
<Link>Classes\Channels\ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived_TimeoutWaitingForChannelCloseMessage.cs</Link>
185+
</Compile>
174186
<Compile Include="..\Renci.SshNet.Tests\Classes\Channels\ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsNotOpen.cs">
175187
<Link>Classes\Channels\ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsNotOpen.cs</Link>
176188
</Compile>
@@ -951,8 +963,23 @@
951963
<Compile Include="..\Renci.SshNet.Tests\Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsZero.cs">
952964
<Link>Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsZero.cs</Link>
953965
</Compile>
954-
<Compile Include="..\Renci.SshNet.Tests\Classes\ServiceFactoryTest_CreateShellStream.cs">
955-
<Link>Classes\ServiceFactoryTest_CreateShellStream.cs</Link>
966+
<Compile Include="..\Renci.SshNet.Tests\Classes\ServiceFactoryTest_CreateShellStream_ChannelOpenThrowsException.cs">
967+
<Link>Classes\ServiceFactoryTest_CreateShellStream_ChannelOpenThrowsException.cs</Link>
968+
</Compile>
969+
<Compile Include="..\Renci.SshNet.Tests\Classes\ServiceFactoryTest_CreateShellStream_SendPseudoTerminalRequestReturnsFalse.cs">
970+
<Link>Classes\ServiceFactoryTest_CreateShellStream_SendPseudoTerminalRequestReturnsFalse.cs</Link>
971+
</Compile>
972+
<Compile Include="..\Renci.SshNet.Tests\Classes\ServiceFactoryTest_CreateShellStream_SendPseudoTerminalRequestThrowsException.cs">
973+
<Link>Classes\ServiceFactoryTest_CreateShellStream_SendPseudoTerminalRequestThrowsException.cs</Link>
974+
</Compile>
975+
<Compile Include="..\Renci.SshNet.Tests\Classes\ServiceFactoryTest_CreateShellStream_SendShellRequestReturnsFalse.cs">
976+
<Link>Classes\ServiceFactoryTest_CreateShellStream_SendShellRequestReturnsFalse.cs</Link>
977+
</Compile>
978+
<Compile Include="..\Renci.SshNet.Tests\Classes\ServiceFactoryTest_CreateShellStream_SendShellRequestThrowsException.cs">
979+
<Link>Classes\ServiceFactoryTest_CreateShellStream_SendShellRequestThrowsException.cs</Link>
980+
</Compile>
981+
<Compile Include="..\Renci.SshNet.Tests\Classes\ServiceFactoryTest_CreateShellStream_Success.cs">
982+
<Link>Classes\ServiceFactoryTest_CreateShellStream_Success.cs</Link>
956983
</Compile>
957984
<Compile Include="..\Renci.SshNet.Tests\Classes\SessionTest.cs">
958985
<Link>Classes\SessionTest.cs</Link>
@@ -987,6 +1014,9 @@
9871014
<Compile Include="..\Renci.SshNet.Tests\Classes\SessionTest_Connected_ServerSendsDisconnectMessageAndShutsDownSocket.cs">
9881015
<Link>Classes\SessionTest_Connected_ServerSendsDisconnectMessageAndShutsDownSocket.cs</Link>
9891016
</Compile>
1017+
<Compile Include="..\Renci.SshNet.Tests\Classes\SessionTest_Connected_ServerSendsUnsupportedMessageType.cs">
1018+
<Link>Classes\SessionTest_Connected_ServerSendsUnsupportedMessageType.cs</Link>
1019+
</Compile>
9901020
<Compile Include="..\Renci.SshNet.Tests\Classes\SessionTest_Connected_ServerShutsDownSendAfterSendingIncompletePacket.cs">
9911021
<Link>Classes\SessionTest_Connected_ServerShutsDownSendAfterSendingIncompletePacket.cs</Link>
9921022
</Compile>
@@ -1710,7 +1740,7 @@
17101740
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
17111741
<ProjectExtensions>
17121742
<VisualStudio>
1713-
<UserProperties ProjectLinkReference="c45379b9-17b1-4e89-bc2e-6d41726413e8" ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" />
1743+
<UserProperties ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" ProjectLinkReference="c45379b9-17b1-4e89-bc2e-6d41726413e8" />
17141744
</VisualStudio>
17151745
</ProjectExtensions>
17161746
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using Microsoft.VisualStudio.TestTools.UnitTesting;
5+
using Moq;
6+
using Renci.SshNet.Channels;
7+
using Renci.SshNet.Common;
8+
9+
namespace Renci.SshNet.Tests.Classes
10+
{
11+
[TestClass]
12+
public class ServiceFactoryTest_CreateShellStream_ChannelOpenThrowsException
13+
{
14+
private Mock<ISession> _sessionMock;
15+
private Mock<IConnectionInfo> _connectionInfoMock;
16+
private Mock<IChannelSession> _channelSessionMock;
17+
private ServiceFactory _serviceFactory;
18+
private string _terminalName;
19+
private uint _columns;
20+
private uint _rows;
21+
private uint _width;
22+
private uint _height;
23+
private IDictionary<TerminalModes, uint> _terminalModeValues;
24+
private int _bufferSize;
25+
private SshException _channelOpenException;
26+
private SshException _actualException;
27+
28+
private void SetupData()
29+
{
30+
var random = new Random();
31+
32+
_terminalName = random.Next().ToString();
33+
_columns = (uint) random.Next();
34+
_rows = (uint) random.Next();
35+
_width = (uint) random.Next();
36+
_height = (uint) random.Next();
37+
_terminalModeValues = new Dictionary<TerminalModes, uint>();
38+
_bufferSize = random.Next();
39+
_channelOpenException = new SshException();
40+
41+
_actualException = null;
42+
}
43+
44+
private void CreateMocks()
45+
{
46+
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
47+
_connectionInfoMock = new Mock<IConnectionInfo>(MockBehavior.Strict);
48+
_channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
49+
}
50+
51+
private void SetupMocks()
52+
{
53+
var sequence = new MockSequence();
54+
55+
_sessionMock.InSequence(sequence)
56+
.Setup(p => p.ConnectionInfo)
57+
.Returns(_connectionInfoMock.Object);
58+
_connectionInfoMock.InSequence(sequence)
59+
.Setup(p => p.Encoding)
60+
.Returns(new UTF8Encoding());
61+
_sessionMock.InSequence(sequence)
62+
.Setup(p => p.CreateChannelSession())
63+
.Returns(_channelSessionMock.Object);
64+
_channelSessionMock.InSequence(sequence)
65+
.Setup(p => p.Open())
66+
.Throws(_channelOpenException);
67+
_channelSessionMock.InSequence(sequence)
68+
.Setup(p => p.Dispose());
69+
}
70+
71+
private void Arrange()
72+
{
73+
SetupData();
74+
CreateMocks();
75+
SetupMocks();
76+
77+
_serviceFactory = new ServiceFactory();
78+
}
79+
80+
[TestInitialize]
81+
public void Initialize()
82+
{
83+
Arrange();
84+
Act();
85+
}
86+
87+
private void Act()
88+
{
89+
try
90+
{
91+
_serviceFactory.CreateShellStream(_sessionMock.Object,
92+
_terminalName,
93+
_columns,
94+
_rows,
95+
_width,
96+
_height,
97+
_terminalModeValues,
98+
_bufferSize);
99+
Assert.Fail();
100+
}
101+
catch (SshException ex)
102+
{
103+
_actualException = ex;
104+
}
105+
}
106+
107+
[TestMethod]
108+
public void CreateShellStreamShouldRethrowExceptionThrownByOpenOnChannelSession()
109+
{
110+
Assert.IsNotNull(_actualException);
111+
Assert.AreSame(_channelOpenException, _actualException);
112+
}
113+
114+
[TestMethod]
115+
public void DisposeOnChannelSessionShouldHaveBeenInvokedOnce()
116+
{
117+
_channelSessionMock.Verify(p => p.Dispose(), Times.Once);
118+
}
119+
}
120+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using Microsoft.VisualStudio.TestTools.UnitTesting;
5+
using Moq;
6+
using Renci.SshNet.Channels;
7+
using Renci.SshNet.Common;
8+
9+
namespace Renci.SshNet.Tests.Classes
10+
{
11+
[TestClass]
12+
public class ServiceFactoryTest_CreateShellStream_SendPseudoTerminalRequestReturnsFalse
13+
{
14+
private Mock<ISession> _sessionMock;
15+
private Mock<IConnectionInfo> _connectionInfoMock;
16+
private Mock<IChannelSession> _channelSessionMock;
17+
private ServiceFactory _serviceFactory;
18+
private string _terminalName;
19+
private uint _columns;
20+
private uint _rows;
21+
private uint _width;
22+
private uint _height;
23+
private IDictionary<TerminalModes, uint> _terminalModeValues;
24+
private int _bufferSize;
25+
private SshException _actualException;
26+
27+
private void SetupData()
28+
{
29+
var random = new Random();
30+
31+
_terminalName = random.Next().ToString();
32+
_columns = (uint)random.Next();
33+
_rows = (uint)random.Next();
34+
_width = (uint)random.Next();
35+
_height = (uint)random.Next();
36+
_terminalModeValues = new Dictionary<TerminalModes, uint>();
37+
_bufferSize = random.Next();
38+
_actualException = null;
39+
}
40+
41+
private void CreateMocks()
42+
{
43+
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
44+
_connectionInfoMock = new Mock<IConnectionInfo>(MockBehavior.Strict);
45+
_channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
46+
}
47+
48+
private void SetupMocks()
49+
{
50+
var sequence = new MockSequence();
51+
52+
_sessionMock.InSequence(sequence)
53+
.Setup(p => p.ConnectionInfo)
54+
.Returns(_connectionInfoMock.Object);
55+
_connectionInfoMock.InSequence(sequence)
56+
.Setup(p => p.Encoding)
57+
.Returns(new UTF8Encoding());
58+
_sessionMock.InSequence(sequence)
59+
.Setup(p => p.CreateChannelSession())
60+
.Returns(_channelSessionMock.Object);
61+
_channelSessionMock.InSequence(sequence)
62+
.Setup(p => p.Open());
63+
_channelSessionMock.InSequence(sequence)
64+
.Setup(p => p.SendPseudoTerminalRequest(_terminalName, _columns, _rows, _width, _height, _terminalModeValues))
65+
.Returns(false);
66+
_channelSessionMock.InSequence(sequence)
67+
.Setup(p => p.Dispose());
68+
}
69+
70+
private void Arrange()
71+
{
72+
SetupData();
73+
CreateMocks();
74+
SetupMocks();
75+
76+
_serviceFactory = new ServiceFactory();
77+
}
78+
79+
[TestInitialize]
80+
public void Initialize()
81+
{
82+
Arrange();
83+
Act();
84+
}
85+
86+
private void Act()
87+
{
88+
try
89+
{
90+
_serviceFactory.CreateShellStream(_sessionMock.Object,
91+
_terminalName,
92+
_columns,
93+
_rows,
94+
_width,
95+
_height,
96+
_terminalModeValues,
97+
_bufferSize);
98+
Assert.Fail();
99+
}
100+
catch (SshException ex)
101+
{
102+
_actualException = ex;
103+
}
104+
}
105+
106+
[TestMethod]
107+
public void CreateShellStreamShouldThrowSshException()
108+
{
109+
Assert.IsNotNull(_actualException);
110+
Assert.IsNull(_actualException.InnerException);
111+
Assert.AreEqual("The pseudo-terminal request was not accepted by the server. Consult the server log for more information.", _actualException.Message);
112+
}
113+
114+
[TestMethod]
115+
public void DisposeOnChannelSessionShouldHaveBeenInvokedOnce()
116+
{
117+
_channelSessionMock.Verify(p => p.Dispose(), Times.Once);
118+
}
119+
}
120+
}

0 commit comments

Comments
 (0)