Skip to content

Commit 8141113

Browse files
committed
Only keep reference to session if the connection was established successfully.
Fixes issue #338.
1 parent 66dcb0b commit 8141113

7 files changed

+306
-38
lines changed

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@
8787
<Compile Include="..\Renci.SshNet.Tests\Classes\BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs">
8888
<Link>Classes\BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs</Link>
8989
</Compile>
90+
<Compile Include="..\Renci.SshNet.Tests\Classes\BaseClientTest_Connect_OnConnectedThrowsException.cs">
91+
<Link>Classes\BaseClientTest_Connect_OnConnectedThrowsException.cs</Link>
92+
</Compile>
9093
<Compile Include="..\Renci.SshNet.Tests\Classes\BaseClientTest_Disconnected_KeepAliveInterval_NotNegativeOne.cs">
9194
<Link>Classes\BaseClientTest_Disconnected_KeepAliveInterval_NotNegativeOne.cs</Link>
9295
</Compile>
@@ -1704,7 +1707,7 @@
17041707
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
17051708
<ProjectExtensions>
17061709
<VisualStudio>
1707-
<UserProperties ProjectLinkReference="c45379b9-17b1-4e89-bc2e-6d41726413e8" ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" />
1710+
<UserProperties ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" ProjectLinkReference="c45379b9-17b1-4e89-bc2e-6d41726413e8" />
17081711
</VisualStudio>
17091712
</ProjectExtensions>
17101713
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
using System;
2+
using System.Reflection;
3+
using System.Threading;
4+
using Microsoft.VisualStudio.TestTools.UnitTesting;
5+
using Moq;
6+
using Renci.SshNet.Common;
7+
using Renci.SshNet.Security;
8+
9+
namespace Renci.SshNet.Tests.Classes
10+
{
11+
[TestClass]
12+
public class BaseClientTest_Connect_OnConnectedThrowsException
13+
{
14+
private Mock<IServiceFactory> _serviceFactoryMock;
15+
private Mock<ISession> _sessionMock;
16+
private MyClient _client;
17+
private ConnectionInfo _connectionInfo;
18+
private ApplicationException _onConnectException;
19+
private ApplicationException _actualException;
20+
21+
[TestInitialize]
22+
public void Setup()
23+
{
24+
Arrange();
25+
Act();
26+
}
27+
28+
[TestCleanup]
29+
public void Cleanup()
30+
{
31+
if (_client != null)
32+
{
33+
_sessionMock.Setup(p => p.OnDisconnecting());
34+
_sessionMock.Setup(p => p.Dispose());
35+
_client.Dispose();
36+
}
37+
}
38+
39+
private void SetupData()
40+
{
41+
_connectionInfo = new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "pwd"));
42+
_onConnectException = new ApplicationException();
43+
}
44+
45+
private void CreateMocks()
46+
{
47+
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
48+
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
49+
}
50+
51+
private void SetupMocks()
52+
{
53+
_serviceFactoryMock.Setup(p => p.CreateSession(_connectionInfo))
54+
.Returns(_sessionMock.Object);
55+
_sessionMock.Setup(p => p.Connect());
56+
_sessionMock.Setup(p => p.Dispose());
57+
}
58+
59+
protected void Arrange()
60+
{
61+
SetupData();
62+
CreateMocks();
63+
SetupMocks();
64+
65+
_client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object)
66+
{
67+
OnConnectedException = _onConnectException
68+
};
69+
}
70+
71+
protected void Act()
72+
{
73+
try
74+
{
75+
_client.Connect();
76+
Assert.Fail();
77+
}
78+
catch (ApplicationException ex)
79+
{
80+
_actualException = ex;
81+
}
82+
}
83+
84+
[TestMethod]
85+
public void ConnectShouldRethrowExceptionThrownByOnConnect()
86+
{
87+
Assert.IsNotNull(_actualException);
88+
Assert.AreSame(_onConnectException, _actualException);
89+
}
90+
91+
[TestMethod]
92+
public void CreateSessionOnServiceFactoryShouldBeInvokedOnce()
93+
{
94+
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo), Times.Once);
95+
}
96+
97+
[TestMethod]
98+
public void ConnectOnSessionShouldBeInvokedOnce()
99+
{
100+
_sessionMock.Verify(p => p.Connect(), Times.Once);
101+
}
102+
103+
[TestMethod]
104+
public void DisposeOnSessionShouldBeInvokedOnce()
105+
{
106+
_sessionMock.Verify(p => p.Dispose(), Times.Once);
107+
}
108+
109+
[TestMethod]
110+
public void ErrorOccuredOnSessionShouldNoLongerBeSignaledViaErrorOccurredOnBaseClient()
111+
{
112+
var errorOccurredSignalCount = 0;
113+
114+
_client.ErrorOccurred += (sender, args) => Interlocked.Increment(ref errorOccurredSignalCount);
115+
116+
_sessionMock.Raise(p => p.ErrorOccured += null, new ExceptionEventArgs(new Exception()));
117+
118+
Assert.AreEqual(0, errorOccurredSignalCount);
119+
}
120+
121+
[TestMethod]
122+
public void HostKeyReceivedOnSessionShouldNoLongerBeSignaledViaHostKeyReceivedOnBaseClient()
123+
{
124+
var hostKeyReceivedSignalCount = 0;
125+
126+
_client.HostKeyReceived += (sender, args) => Interlocked.Increment(ref hostKeyReceivedSignalCount);
127+
128+
_sessionMock.Raise(p => p.HostKeyReceived += null, new HostKeyEventArgs(GetKeyHostAlgorithm()));
129+
130+
Assert.AreEqual(0, hostKeyReceivedSignalCount);
131+
}
132+
133+
[TestMethod]
134+
public void SessionShouldBeNull()
135+
{
136+
Assert.IsNull(_client.Session);
137+
}
138+
139+
[TestMethod]
140+
public void IsConnectedShouldReturnFalse()
141+
{
142+
Assert.IsFalse(_client.IsConnected);
143+
}
144+
145+
private static KeyHostAlgorithm GetKeyHostAlgorithm()
146+
{
147+
var executingAssembly = Assembly.GetExecutingAssembly();
148+
149+
using (var s = executingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", "Key.RSA.txt")))
150+
{
151+
var privateKey = new PrivateKeyFile(s);
152+
return (KeyHostAlgorithm) privateKey.HostKey;
153+
}
154+
}
155+
156+
private class MyClient : BaseClient
157+
{
158+
private int _onConnectedCount;
159+
160+
public MyClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, IServiceFactory serviceFactory) : base(connectionInfo, ownsConnectionInfo, serviceFactory)
161+
{
162+
}
163+
164+
public Exception OnConnectedException { get; set; }
165+
166+
protected override void OnConnected()
167+
{
168+
base.OnConnected();
169+
170+
Interlocked.Increment(ref _onConnectedCount);
171+
172+
if (OnConnectedException != null)
173+
{
174+
throw OnConnectedException;
175+
}
176+
}
177+
}
178+
179+
180+
}
181+
}

src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Connected.cs

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Globalization;
4-
using System.Text;
54
using Microsoft.VisualStudio.TestTools.UnitTesting;
65
using Moq;
76
using Renci.SshNet.Channels;
@@ -46,10 +45,9 @@ protected void Arrange()
4645
_channelMock.InSequence(_sequence).Setup(p => p.SendSubsystemRequest(_subsystemName)).Returns(true);
4746
_channelMock.InSequence(_sequence).Setup(p => p.IsOpen).Returns(true);
4847

49-
_subsystemSession = new SubsystemSessionStub(
50-
_sessionMock.Object,
51-
_subsystemName,
52-
_operationTimeout);
48+
_subsystemSession = new SubsystemSessionStub(_sessionMock.Object,
49+
_subsystemName,
50+
_operationTimeout);
5351
_subsystemSession.Disconnected += (sender, args) => _disconnectedRegister.Add(args);
5452
_subsystemSession.ErrorOccurred += (sender, args) => _errorOccurredRegister.Add(args);
5553
_subsystemSession.Connect();

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

+1
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
<Compile Include="Classes\BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs" />
9292
<Compile Include="Classes\BaseClientTest_Connected_KeepAliveInterval_NegativeOne.cs" />
9393
<Compile Include="Classes\BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs" />
94+
<Compile Include="Classes\BaseClientTest_Connect_OnConnectedThrowsException.cs" />
9495
<Compile Include="Classes\BaseClientTest_Disconnected_KeepAliveInterval_NotNegativeOne.cs" />
9596
<Compile Include="Classes\BaseClientTest_NotConnected_KeepAliveInterval_NotNegativeOne.cs" />
9697
<Compile Include="Classes\Channels\ChannelDirectTcpipTest.cs" />

0 commit comments

Comments
 (0)