Skip to content

Commit

Permalink
When the request to open a subsystem fails, close the channel session…
Browse files Browse the repository at this point in the history
… and throw a SshException.

Fixes sshnet#308.
  • Loading branch information
drieseng committed Nov 15, 2017
1 parent 7cecd86 commit 66471e6
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 2 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 @@ -1551,6 +1551,9 @@
<Compile Include="..\Renci.SshNet.Tests\Classes\SubsystemSession_Connect_NeverConnected.cs">
<Link>Classes\SubsystemSession_Connect_NeverConnected.cs</Link>
</Compile>
<Compile Include="..\Renci.SshNet.Tests\Classes\SubsystemSession_Connect_SendSubsystemRequestFails.cs">
<Link>Classes\SubsystemSession_Connect_SendSubsystemRequestFails.cs</Link>
</Compile>
<Compile Include="..\Renci.SshNet.Tests\Classes\SubsystemSession_Disconnect_Connected.cs">
<Link>Classes\SubsystemSession_Disconnect_Connected.cs</Link>
</Compile>
Expand Down Expand Up @@ -1707,7 +1710,7 @@
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
<UserProperties ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" ProjectLinkReference="c45379b9-17b1-4e89-bc2e-6d41726413e8" />
<UserProperties ProjectLinkReference="c45379b9-17b1-4e89-bc2e-6d41726413e8" ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" />
</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,122 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Channels;
using Renci.SshNet.Common;

namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class SubsystemSession_Connect_SendSubsystemRequestFails
{
private Mock<ISession> _sessionMock;
private Mock<IChannelSession> _channelMock;
private string _subsystemName;
private SubsystemSessionStub _subsystemSession;
private int _operationTimeout;
private IList<EventArgs> _disconnectedRegister;
private IList<ExceptionEventArgs> _errorOccurredRegister;
private SshException _actualException;
private MockSequence _sequence;

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

protected void Arrange()
{
var random = new Random();
_subsystemName = random.Next().ToString(CultureInfo.InvariantCulture);
_operationTimeout = 30000;
_disconnectedRegister = new List<EventArgs>();
_errorOccurredRegister = new List<ExceptionEventArgs>();

_sessionMock = new Mock<ISession>(MockBehavior.Strict);
_channelMock = new Mock<IChannelSession>(MockBehavior.Strict);

_sequence = new MockSequence();
_sessionMock.InSequence(_sequence).Setup(p => p.CreateChannelSession()).Returns(_channelMock.Object);
_channelMock.InSequence(_sequence).Setup(p => p.Open());
_channelMock.InSequence(_sequence).Setup(p => p.SendSubsystemRequest(_subsystemName)).Returns(false);
_channelMock.InSequence(_sequence).Setup(p => p.Dispose());

_subsystemSession = new SubsystemSessionStub(_sessionMock.Object,
_subsystemName,
_operationTimeout);
_subsystemSession.Disconnected += (sender, args) => _disconnectedRegister.Add(args);
_subsystemSession.ErrorOccurred += (sender, args) => _errorOccurredRegister.Add(args);
}

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

[TestMethod]
public void ConnectShouldHaveThrownSshException()
{
Assert.IsNotNull(_actualException);
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual(string.Format(CultureInfo.InvariantCulture, "Subsystem '{0}' could not be executed.", _subsystemName), _actualException.Message);
}

[TestMethod]
public void ChannelShouldBeNull()
{
Assert.IsNull(_subsystemSession.Channel);
}

[TestMethod]
public void DisconnectHasNeverFired()
{
Assert.AreEqual(0, _disconnectedRegister.Count);
}

[TestMethod]
public void ErrorOccurredHasNeverFired()
{
Assert.AreEqual(0, _errorOccurredRegister.Count);
}

[TestMethod]
public void IsOpenShouldReturnFalse()
{
Assert.IsFalse(_subsystemSession.IsOpen);
}

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

[TestMethod]
public void ErrorOccuredOnSessionShouldNoLongerBeSignaledViaErrorOccurredOnSubsystemSession()
{
_sessionMock.Raise(p => p.ErrorOccured += null, new ExceptionEventArgs(new Exception()));

Assert.AreEqual(0, _errorOccurredRegister.Count);
}

[TestMethod]
public void DisconnectedOnSessionShouldNoLongerBeSignaledViaDisconnectedOnSubsystemSession()
{
_sessionMock.Raise(p => p.Disconnected += null, new EventArgs());

Assert.AreEqual(0, _disconnectedRegister.Count);
}
}
}
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 @@ -553,6 +553,7 @@
<Compile Include="Classes\SubsystemSession_Connect_Disconnected.cs" />
<Compile Include="Classes\SubsystemSession_Connect_Disposed.cs" />
<Compile Include="Classes\SubsystemSession_Connect_NeverConnected.cs" />
<Compile Include="Classes\SubsystemSession_Connect_SendSubsystemRequestFails.cs" />
<Compile Include="Classes\SubsystemSession_Disconnect_Connected.cs" />
<Compile Include="Classes\SubsystemSession_Disconnect_Disposed.cs" />
<Compile Include="Classes\SubsystemSession_Disconnect_NeverConnected.cs" />
Expand Down
12 changes: 11 additions & 1 deletion src/Renci.SshNet/SubsystemSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ protected SubsystemSession(ISession session, string subsystemName, int operation
/// </summary>
/// <exception cref="InvalidOperationException">The session is already connected.</exception>
/// <exception cref="ObjectDisposedException">The method was called after the session was disposed.</exception>
/// <exception cref="SshException">The channel session could not be opened, or the subsystem could not be executed.</exception>
public void Connect()
{
EnsureNotDisposed();
Expand All @@ -116,7 +117,16 @@ public void Connect()
_channel.Exception += Channel_Exception;
_channel.Closed += Channel_Closed;
_channel.Open();
_channel.SendSubsystemRequest(_subsystemName);

if (!_channel.SendSubsystemRequest(_subsystemName))
{
// close channel session
Disconnect();
// signal subsystem failure
throw new SshException(string.Format(CultureInfo.InvariantCulture,
"Subsystem '{0}' could not be executed.",
_subsystemName));
}

OnChannelOpen();
}
Expand Down

0 comments on commit 66471e6

Please sign in to comment.