Skip to content

Commit

Permalink
Only keep reference to session if the connection was established succ…
Browse files Browse the repository at this point in the history
…essfully.

Fixes issue sshnet#338.
  • Loading branch information
drieseng committed Nov 11, 2017
1 parent 66dcb0b commit 8141113
Show file tree
Hide file tree
Showing 7 changed files with 306 additions and 38 deletions.
5 changes: 4 additions & 1 deletion src/Renci.SshNet.Tests.NET35/Renci.SshNet.Tests.NET35.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@
<Compile Include="..\Renci.SshNet.Tests\Classes\BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs">
<Link>Classes\BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs</Link>
</Compile>
<Compile Include="..\Renci.SshNet.Tests\Classes\BaseClientTest_Connect_OnConnectedThrowsException.cs">
<Link>Classes\BaseClientTest_Connect_OnConnectedThrowsException.cs</Link>
</Compile>
<Compile Include="..\Renci.SshNet.Tests\Classes\BaseClientTest_Disconnected_KeepAliveInterval_NotNegativeOne.cs">
<Link>Classes\BaseClientTest_Disconnected_KeepAliveInterval_NotNegativeOne.cs</Link>
</Compile>
Expand Down Expand Up @@ -1704,7 +1707,7 @@
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
<UserProperties ProjectLinkReference="c45379b9-17b1-4e89-bc2e-6d41726413e8" ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" />
<UserProperties ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" ProjectLinkReference="c45379b9-17b1-4e89-bc2e-6d41726413e8" />
</VisualStudio>
</ProjectExtensions>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
using System;
using System.Reflection;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using Renci.SshNet.Security;

namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class BaseClientTest_Connect_OnConnectedThrowsException
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private MyClient _client;
private ConnectionInfo _connectionInfo;
private ApplicationException _onConnectException;
private ApplicationException _actualException;

[TestInitialize]
public void Setup()
{
Arrange();
Act();
}

[TestCleanup]
public void Cleanup()
{
if (_client != null)
{
_sessionMock.Setup(p => p.OnDisconnecting());
_sessionMock.Setup(p => p.Dispose());
_client.Dispose();
}
}

private void SetupData()
{
_connectionInfo = new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "pwd"));
_onConnectException = new ApplicationException();
}

private void CreateMocks()
{
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
}

private void SetupMocks()
{
_serviceFactoryMock.Setup(p => p.CreateSession(_connectionInfo))
.Returns(_sessionMock.Object);
_sessionMock.Setup(p => p.Connect());
_sessionMock.Setup(p => p.Dispose());
}

protected void Arrange()
{
SetupData();
CreateMocks();
SetupMocks();

_client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object)
{
OnConnectedException = _onConnectException
};
}

protected void Act()
{
try
{
_client.Connect();
Assert.Fail();
}
catch (ApplicationException ex)
{
_actualException = ex;
}
}

[TestMethod]
public void ConnectShouldRethrowExceptionThrownByOnConnect()
{
Assert.IsNotNull(_actualException);
Assert.AreSame(_onConnectException, _actualException);
}

[TestMethod]
public void CreateSessionOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo), Times.Once);
}

[TestMethod]
public void ConnectOnSessionShouldBeInvokedOnce()
{
_sessionMock.Verify(p => p.Connect(), Times.Once);
}

[TestMethod]
public void DisposeOnSessionShouldBeInvokedOnce()
{
_sessionMock.Verify(p => p.Dispose(), Times.Once);
}

[TestMethod]
public void ErrorOccuredOnSessionShouldNoLongerBeSignaledViaErrorOccurredOnBaseClient()
{
var errorOccurredSignalCount = 0;

_client.ErrorOccurred += (sender, args) => Interlocked.Increment(ref errorOccurredSignalCount);

_sessionMock.Raise(p => p.ErrorOccured += null, new ExceptionEventArgs(new Exception()));

Assert.AreEqual(0, errorOccurredSignalCount);
}

[TestMethod]
public void HostKeyReceivedOnSessionShouldNoLongerBeSignaledViaHostKeyReceivedOnBaseClient()
{
var hostKeyReceivedSignalCount = 0;

_client.HostKeyReceived += (sender, args) => Interlocked.Increment(ref hostKeyReceivedSignalCount);

_sessionMock.Raise(p => p.HostKeyReceived += null, new HostKeyEventArgs(GetKeyHostAlgorithm()));

Assert.AreEqual(0, hostKeyReceivedSignalCount);
}

[TestMethod]
public void SessionShouldBeNull()
{
Assert.IsNull(_client.Session);
}

[TestMethod]
public void IsConnectedShouldReturnFalse()
{
Assert.IsFalse(_client.IsConnected);
}

private static KeyHostAlgorithm GetKeyHostAlgorithm()
{
var executingAssembly = Assembly.GetExecutingAssembly();

using (var s = executingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", "Key.RSA.txt")))
{
var privateKey = new PrivateKeyFile(s);
return (KeyHostAlgorithm) privateKey.HostKey;
}
}

private class MyClient : BaseClient
{
private int _onConnectedCount;

public MyClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, IServiceFactory serviceFactory) : base(connectionInfo, ownsConnectionInfo, serviceFactory)
{
}

public Exception OnConnectedException { get; set; }

protected override void OnConnected()
{
base.OnConnected();

Interlocked.Increment(ref _onConnectedCount);

if (OnConnectedException != null)
{
throw OnConnectedException;
}
}
}


}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Channels;
Expand Down Expand Up @@ -46,10 +45,9 @@ protected void Arrange()
_channelMock.InSequence(_sequence).Setup(p => p.SendSubsystemRequest(_subsystemName)).Returns(true);
_channelMock.InSequence(_sequence).Setup(p => p.IsOpen).Returns(true);

_subsystemSession = new SubsystemSessionStub(
_sessionMock.Object,
_subsystemName,
_operationTimeout);
_subsystemSession = new SubsystemSessionStub(_sessionMock.Object,
_subsystemName,
_operationTimeout);
_subsystemSession.Disconnected += (sender, args) => _disconnectedRegister.Add(args);
_subsystemSession.ErrorOccurred += (sender, args) => _errorOccurredRegister.Add(args);
_subsystemSession.Connect();
Expand Down
1 change: 1 addition & 0 deletions src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
<Compile Include="Classes\BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs" />
<Compile Include="Classes\BaseClientTest_Connected_KeepAliveInterval_NegativeOne.cs" />
<Compile Include="Classes\BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs" />
<Compile Include="Classes\BaseClientTest_Connect_OnConnectedThrowsException.cs" />
<Compile Include="Classes\BaseClientTest_Disconnected_KeepAliveInterval_NotNegativeOne.cs" />
<Compile Include="Classes\BaseClientTest_NotConnected_KeepAliveInterval_NotNegativeOne.cs" />
<Compile Include="Classes\Channels\ChannelDirectTcpipTest.cs" />
Expand Down
Loading

0 comments on commit 8141113

Please sign in to comment.