Complete refactoring of connection process, and greatly improve test coverage.

This commit is contained in:
drieseng
2020-12-29 20:01:28 +01:00
parent e0b32a41ea
commit 60be75d85c
103 changed files with 6449 additions and 1575 deletions
@@ -0,0 +1,35 @@
using Moq;
using Renci.SshNet.Connection;
using Renci.SshNet.Tests.Common;
namespace Renci.SshNet.Tests.Classes
{
public abstract class BaseClientTestBase : TripleATestBase
{
internal Mock<IServiceFactory> _serviceFactoryMock { get; private set; }
internal Mock<ISocketFactory> _socketFactoryMock { get; private set; }
internal Mock<ISession> _sessionMock { get; private set; }
protected virtual void CreateMocks()
{
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
_socketFactoryMock = new Mock<ISocketFactory>(MockBehavior.Strict);
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
}
protected virtual void SetupData()
{
}
protected virtual void SetupMocks()
{
}
protected override void Arrange()
{
CreateMocks();
SetupData();
SetupMocks();
}
}
}
@@ -9,24 +9,30 @@ using Renci.SshNet.Security;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class BaseClientTest_Connect_OnConnectedThrowsException
public class BaseClientTest_Connect_OnConnectedThrowsException : BaseClientTestBase
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private MyClient _client;
private ConnectionInfo _connectionInfo;
private ApplicationException _onConnectException;
private ApplicationException _actualException;
[TestInitialize]
public void Setup()
protected override void SetupData()
{
Arrange();
Act();
_connectionInfo = new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "pwd"));
_onConnectException = new ApplicationException();
}
[TestCleanup]
public void Cleanup()
protected override void SetupMocks()
{
_serviceFactoryMock.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.Setup(p => p.Connect());
_sessionMock.Setup(p => p.Dispose());
}
protected override void TearDown()
{
if (_client != null)
{
@@ -36,31 +42,9 @@ namespace Renci.SshNet.Tests.Classes
}
}
private void SetupData()
protected override void Arrange()
{
_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();
base.Arrange();
_client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object)
{
@@ -68,7 +52,7 @@ namespace Renci.SshNet.Tests.Classes
};
}
protected void Act()
protected override void Act()
{
try
{
@@ -88,10 +72,17 @@ namespace Renci.SshNet.Tests.Classes
Assert.AreSame(_onConnectException, _actualException);
}
[TestMethod]
public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once);
}
[TestMethod]
public void CreateSessionOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo), Times.Once);
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object),
Times.Once);
}
[TestMethod]
@@ -2,29 +2,49 @@
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Connection;
using Renci.SshNet.Messages.Transport;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class BaseClientTest_Connected_KeepAliveInterval_NegativeOne
public class BaseClientTest_Connected_KeepAliveInterval_NegativeOne : BaseClientTestBase
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private BaseClient _client;
private ConnectionInfo _connectionInfo;
private TimeSpan _keepAliveInterval;
private int _keepAliveCount;
[TestInitialize]
public void Setup()
protected override void SetupData()
{
Arrange();
Act();
_connectionInfo = new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "pwd"));
_keepAliveInterval = TimeSpan.FromMilliseconds(100d);
_keepAliveCount = 0;
}
[TestCleanup]
public void Cleanup()
protected override void SetupMocks()
{
_serviceFactoryMock.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.Setup(p => p.Connect());
_sessionMock.Setup(p => p.IsConnected).Returns(true);
_sessionMock.Setup(p => p.TrySendMessage(It.IsAny<IgnoreMessage>()))
.Returns(true)
.Callback(() => Interlocked.Increment(ref _keepAliveCount));
}
protected override void Arrange()
{
base.Arrange();
_client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object);
_client.Connect();
_client.KeepAliveInterval = _keepAliveInterval;
}
protected override void TearDown()
{
if (_client != null)
{
@@ -34,42 +54,7 @@ namespace Renci.SshNet.Tests.Classes
}
}
private void SetupData()
{
_connectionInfo = new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "pwd"));
_keepAliveInterval = TimeSpan.FromMilliseconds(100d);
_keepAliveCount = 0;
}
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.IsConnected).Returns(true);
_sessionMock.Setup(p => p.TrySendMessage(It.IsAny<IgnoreMessage>()))
.Returns(true)
.Callback(() => Interlocked.Increment(ref _keepAliveCount));
}
protected void Arrange()
{
SetupData();
CreateMocks();
SetupMocks();
_client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object);
_client.Connect();
_client.KeepAliveInterval = _keepAliveInterval;
}
protected void Act()
protected override void Act()
{
// allow keep-alive to be sent once
Thread.Sleep(150);
@@ -84,10 +69,16 @@ namespace Renci.SshNet.Tests.Classes
Assert.AreEqual(TimeSpan.FromMilliseconds(-1), _client.KeepAliveInterval);
}
[TestMethod]
public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once);
}
[TestMethod]
public void CreateSessionOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo), Times.Once);
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object), Times.Once);
}
[TestMethod]
@@ -7,24 +7,42 @@ using Renci.SshNet.Messages.Transport;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne
public class BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne : BaseClientTestBase
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private BaseClient _client;
private ConnectionInfo _connectionInfo;
private TimeSpan _keepAliveInterval;
private int _keepAliveCount;
[TestInitialize]
public void Setup()
protected override void SetupData()
{
Arrange();
Act();
_connectionInfo = new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "pwd"));
_keepAliveInterval = TimeSpan.FromMilliseconds(50d);
_keepAliveCount = 0;
}
[TestCleanup]
public void Cleanup()
protected override void SetupMocks()
{
_serviceFactoryMock.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.Setup(p => p.Connect());
_sessionMock.Setup(p => p.IsConnected).Returns(true);
_sessionMock.Setup(p => p.TrySendMessage(It.IsAny<IgnoreMessage>()))
.Returns(true)
.Callback(() => Interlocked.Increment(ref _keepAliveCount));
}
protected override void Arrange()
{
base.Arrange();
_client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object);
_client.Connect();
}
protected override void TearDown()
{
if (_client != null)
{
@@ -34,41 +52,7 @@ namespace Renci.SshNet.Tests.Classes
}
}
private void SetupData()
{
_connectionInfo = new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "pwd"));
_keepAliveInterval = TimeSpan.FromMilliseconds(50d);
_keepAliveCount = 0;
}
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.IsConnected).Returns(true);
_sessionMock.Setup(p => p.TrySendMessage(It.IsAny<IgnoreMessage>()))
.Returns(true)
.Callback(() => Interlocked.Increment(ref _keepAliveCount));
}
protected void Arrange()
{
SetupData();
CreateMocks();
SetupMocks();
_client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object);
_client.Connect();
}
protected void Act()
protected override void Act()
{
_client.KeepAliveInterval = _keepAliveInterval;
@@ -82,10 +66,17 @@ namespace Renci.SshNet.Tests.Classes
Assert.AreEqual(_keepAliveInterval, _client.KeepAliveInterval);
}
[TestMethod]
public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once);
}
[TestMethod]
public void CreateSessionOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo), Times.Once);
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object),
Times.Once);
}
[TestMethod]
@@ -7,24 +7,53 @@ using Renci.SshNet.Messages.Transport;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class BaseClientTest_Connected_KeepAlivesNotSentConcurrently
public class BaseClientTest_Connected_KeepAlivesNotSentConcurrently : BaseClientTestBase
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private MockSequence _mockSequence;
private BaseClient _client;
private ConnectionInfo _connectionInfo;
private ManualResetEvent _keepAliveSent;
[TestInitialize]
public void Setup()
protected override void SetupData()
{
Arrange();
Act();
_connectionInfo = new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "pwd"));
_keepAliveSent = new ManualResetEvent(false);
}
[TestCleanup]
public void Cleanup()
protected override void SetupMocks()
{
_mockSequence = new MockSequence();
_serviceFactoryMock.InSequence(_mockSequence)
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.InSequence(_mockSequence)
.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(_mockSequence)
.Setup(p => p.Connect());
_sessionMock.InSequence(_mockSequence)
.Setup(p => p.TrySendMessage(It.IsAny<IgnoreMessage>()))
.Returns(true)
.Callback(() =>
{
Thread.Sleep(300);
_keepAliveSent.Set();
});
}
protected override void Arrange()
{
base.Arrange();
_client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object)
{
KeepAliveInterval = TimeSpan.FromMilliseconds(50d)
};
_client.Connect();
}
protected override void TearDown()
{
if (_client != null)
{
@@ -34,47 +63,7 @@ namespace Renci.SshNet.Tests.Classes
}
}
private void SetupData()
{
_connectionInfo = new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "pwd"));
_keepAliveSent = new ManualResetEvent(false);
}
private void CreateMocks()
{
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
}
private void SetupMocks()
{
_mockSequence = new MockSequence();
_serviceFactoryMock.InSequence(_mockSequence).Setup(p => p.CreateSession(_connectionInfo)).Returns(_sessionMock.Object);
_sessionMock.InSequence(_mockSequence).Setup(p => p.Connect());
_sessionMock.InSequence(_mockSequence).Setup(p => p.TrySendMessage(It.IsAny<IgnoreMessage>()))
.Returns(true)
.Callback(() =>
{
Thread.Sleep(300);
_keepAliveSent.Set();
});
}
protected void Arrange()
{
SetupData();
CreateMocks();
SetupMocks();
_client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object)
{
KeepAliveInterval = TimeSpan.FromMilliseconds(50d)
};
_client.Connect();
}
protected void Act()
protected override void Act()
{
// should keep-alive message be sent concurrently, then multiple keep-alive
// message would be sent during this sleep period
@@ -0,0 +1,107 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Connection;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class BaseClientTest_Disconnected_Connect : BaseClientTestBase
{
private Mock<ISocketFactory> _socketFactory2Mock;
private Mock<ISession> _session2Mock;
private BaseClient _client;
private ConnectionInfo _connectionInfo;
protected override void SetupData()
{
_connectionInfo = new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "pwd"));
}
protected override void CreateMocks()
{
base.CreateMocks();
_socketFactory2Mock = new Mock<ISocketFactory>(MockBehavior.Strict);
_session2Mock = new Mock<ISession>(MockBehavior.Strict);
}
protected override void SetupMocks()
{
var sequence = new MockSequence();
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence)
.Setup(p => p.Connect());
_sessionMock.InSequence(sequence)
.Setup(p => p.OnDisconnecting());
_sessionMock.InSequence(sequence)
.Setup(p => p.Dispose());
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactory2Mock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo, _socketFactory2Mock.Object))
.Returns(_session2Mock.Object);
_session2Mock.InSequence(sequence)
.Setup(p => p.Connect());
}
protected override void Arrange()
{
base.Arrange();
_client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object);
_client.Connect();
_client.Disconnect();
}
protected override void TearDown()
{
if (_client != null)
{
_session2Mock.Setup(p => p.OnDisconnecting());
_session2Mock.Setup(p => p.Dispose());
_client.Dispose();
}
}
protected override void Act()
{
_client.Connect();
}
[TestMethod]
public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedTwic()
{
_serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Exactly(2));
}
[TestMethod]
public void CreateSessionOnServiceFactoryShouldBeInvokedTwice()
{
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object),
Times.Once);
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactory2Mock.Object),
Times.Once);
}
[TestMethod]
public void ConnectOnSessionShouldBeInvokedTwice()
{
_sessionMock.Verify(p => p.Connect(), Times.Once);
_session2Mock.Verify(p => p.Connect(), Times.Once);
}
private class MyClient : BaseClient
{
public MyClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, IServiceFactory serviceFactory) : base(connectionInfo, ownsConnectionInfo, serviceFactory)
{
}
}
}
}
@@ -7,23 +7,39 @@ using Renci.SshNet.Messages.Transport;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class BaseClientTest_Disconnected_KeepAliveInterval_NotNegativeOne
public class BaseClientTest_Disconnected_KeepAliveInterval_NotNegativeOne : BaseClientTestBase
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private BaseClient _client;
private ConnectionInfo _connectionInfo;
private TimeSpan _keepAliveInterval;
[TestInitialize]
public void Setup()
protected override void SetupData()
{
Arrange();
Act();
_connectionInfo = new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "pwd"));
_keepAliveInterval = TimeSpan.FromMilliseconds(50d);
}
[TestCleanup]
public void Cleanup()
protected override void SetupMocks()
{
_serviceFactoryMock.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.Setup(p => p.Connect());
_sessionMock.Setup(p => p.IsConnected).Returns(false);
_sessionMock.Setup(p => p.TrySendMessage(It.IsAny<IgnoreMessage>()))
.Returns(true);
}
protected override void Arrange()
{
base.Arrange();
_client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object);
_client.Connect();
}
protected override void TearDown()
{
if (_client != null)
{
@@ -33,39 +49,7 @@ namespace Renci.SshNet.Tests.Classes
}
}
private void SetupData()
{
_connectionInfo = new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "pwd"));
_keepAliveInterval = TimeSpan.FromMilliseconds(50d);
}
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.IsConnected).Returns(false);
_sessionMock.Setup(p => p.TrySendMessage(It.IsAny<IgnoreMessage>()))
.Returns(true);
}
protected void Arrange()
{
SetupData();
CreateMocks();
SetupMocks();
_client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object);
_client.Connect();
}
protected void Act()
protected override void Act()
{
_client.KeepAliveInterval = _keepAliveInterval;
@@ -79,10 +63,17 @@ namespace Renci.SshNet.Tests.Classes
Assert.AreEqual(_keepAliveInterval, _client.KeepAliveInterval);
}
[TestMethod]
public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once);
}
[TestMethod]
public void CreateSessionOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo), Times.Once);
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object),
Times.Once);
}
[TestMethod]
@@ -7,24 +7,28 @@ using Renci.SshNet.Messages.Transport;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class BaseClientTest_NotConnected_KeepAliveInterval_NotNegativeOne
public class BaseClientTest_NotConnected_KeepAliveInterval_NotNegativeOne : BaseClientTestBase
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private BaseClient _client;
private ConnectionInfo _connectionInfo;
private TimeSpan _keepAliveInterval;
private int _keepAliveCount;
[TestInitialize]
public void Setup()
protected override void SetupData()
{
Arrange();
Act();
_connectionInfo = new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "pwd"));
_keepAliveInterval = TimeSpan.FromMilliseconds(100d);
_keepAliveCount = 0;
}
[TestCleanup]
public void Cleanup()
protected override void Arrange()
{
base.Arrange();
_client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object);
}
protected override void TearDown()
{
if (_client != null)
{
@@ -34,33 +38,7 @@ namespace Renci.SshNet.Tests.Classes
}
}
private void SetupData()
{
_connectionInfo = new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "pwd"));
_keepAliveInterval = TimeSpan.FromMilliseconds(100d);
_keepAliveCount = 0;
}
private void CreateMocks()
{
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
}
private static void SetupMocks()
{
}
protected void Arrange()
{
SetupData();
CreateMocks();
SetupMocks();
_client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object);
}
protected void Act()
protected override void Act()
{
_client.KeepAliveInterval = _keepAliveInterval;
@@ -77,7 +55,10 @@ namespace Renci.SshNet.Tests.Classes
[TestMethod]
public void ConnectShouldActivateKeepAliveIfSessionIs()
{
_serviceFactoryMock.Setup(p => p.CreateSession(_connectionInfo)).Returns(_sessionMock.Object);
_serviceFactoryMock.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.Setup(p => p.Connect());
_sessionMock.Setup(p => p.TrySendMessage(It.IsAny<IgnoreMessage>()))
.Returns(true)
@@ -0,0 +1,44 @@
using Moq;
using Renci.SshNet.Connection;
using Renci.SshNet.Tests.Common;
using System.Net;
namespace Renci.SshNet.Tests.Classes.Connection
{
public abstract class DirectConnectorTestBase : TripleATestBase
{
internal Mock<ISocketFactory> SocketFactoryMock { get; private set; }
internal DirectConnector Connector { get; private set; }
internal SocketFactory SocketFactory { get; private set; }
protected virtual void CreateMocks()
{
SocketFactoryMock = new Mock<ISocketFactory>(MockBehavior.Strict);
}
protected virtual void SetupData()
{
Connector = new DirectConnector(SocketFactoryMock.Object);
SocketFactory = new SocketFactory();
}
protected virtual void SetupMocks()
{
}
protected sealed override void Arrange()
{
CreateMocks();
SetupData();
SetupMocks();
}
protected ConnectionInfo CreateConnectionInfo(string hostName)
{
return new ConnectionInfo(hostName,
777,
"user",
new KeyboardInteractiveAuthenticationMethod("user"));
}
}
}
@@ -0,0 +1,103 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class DirectConnectorTest_Connect_ConnectionRefusedByServer : DirectConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private SocketException _actualException;
private Socket _clientSocket;
private Stopwatch _stopWatch;
protected override void SetupData()
{
base.SetupData();
_connectionInfo = CreateConnectionInfo(IPAddress.Loopback.ToString());
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(5000);
_stopWatch = new Stopwatch();
_actualException = null;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_clientSocket != null)
{
_clientSocket.Dispose();
}
}
protected override void Act()
{
_stopWatch.Start();
try
{
Connector.Connect(_connectionInfo);
Assert.Fail();
}
catch (SocketException ex)
{
_actualException = ex;
}
finally
{
_stopWatch.Stop();
}
}
[TestMethod]
public void ConnectShouldHaveThrownSocketException()
{
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual(SocketError.ConnectionRefused, _actualException.SocketErrorCode);
}
[TestMethod]
public void ConnectShouldHaveRespectedTimeout()
{
var errorText = string.Format("Elapsed: {0}, Timeout: {1}",
_stopWatch.ElapsedMilliseconds,
_connectionInfo.Timeout.TotalMilliseconds);
Assert.IsTrue(_stopWatch.ElapsedMilliseconds < _connectionInfo.Timeout.TotalMilliseconds, errorText);
}
[TestMethod]
public void ClientSocketShouldHaveBeenDisposed()
{
try
{
_clientSocket.Receive(new byte[0]);
Assert.Fail();
}
catch (ObjectDisposedException)
{
}
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,118 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using Renci.SshNet.Tests.Common;
using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class DirectConnectorTest_Connect_ConnectionSucceeded : DirectConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private AsyncSocketListener _server;
private Socket _clientSocket;
private Stopwatch _stopWatch;
private bool _disconnected;
private Socket _actual;
protected override void SetupData()
{
base.SetupData();
var random = new Random();
_connectionInfo = CreateConnectionInfo(IPAddress.Loopback.ToString());
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(random.Next(50, 200));
_stopWatch = new Stopwatch();
_disconnected = false;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_server = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.Port));
_server.Disconnected += (socket) => _disconnected = true;
_server.Connected += (socket) => socket.Send(new byte[1] { 0x44 });
_server.Start();
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_server != null)
{
_server.Dispose();
}
if (_clientSocket != null)
{
_clientSocket.Dispose();
}
}
protected override void Act()
{
_stopWatch.Start();
try
{
_actual = Connector.Connect(_connectionInfo);
}
finally
{
_stopWatch.Stop();
}
}
[TestMethod]
public void ConnectShouldHaveReturnedSocketCreatedUsingSocketFactory()
{
Assert.IsNotNull(_actual);
Assert.AreSame(_clientSocket, _actual);
}
[TestMethod]
public void ConnectShouldHaveRespectedTimeout()
{
var errorText = string.Format("Elapsed: {0}, Timeout: {1}",
_stopWatch.ElapsedMilliseconds,
_connectionInfo.Timeout.TotalMilliseconds);
Assert.IsTrue(_stopWatch.ElapsedMilliseconds < (_connectionInfo.Timeout.TotalMilliseconds + 100), errorText);
}
[TestMethod]
public void ClientSocketShouldBeConnected()
{
Assert.IsTrue(_clientSocket.Connected);
Assert.IsFalse(_disconnected);
}
[TestMethod]
public void NoBytesShouldHaveBeenReadFromSocket()
{
var buffer = new byte[1];
var bytesRead = _clientSocket.Receive(buffer);
Assert.AreEqual(1, bytesRead);
Assert.AreEqual(0x44, buffer[0]);
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,42 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System.Net.Sockets;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class DirectConnectorTest_Connect_HostNameInvalid : DirectConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private SocketException _actualException;
protected override void SetupData()
{
base.SetupData();
_connectionInfo = CreateConnectionInfo("invalid.");
_actualException = null;
}
protected override void Act()
{
try
{
Connector.Connect(_connectionInfo);
Assert.Fail();
}
catch (SocketException ex)
{
_actualException = ex;
}
}
[TestMethod]
public void ConnectShouldHaveThrownSocketException()
{
Assert.IsNotNull(_actualException);
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual(SocketError.HostNotFound, _actualException.SocketErrorCode);
}
}
}
@@ -0,0 +1,108 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using Renci.SshNet.Tests.Common;
using System;
using System.Diagnostics;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class DirectConnectorTest_Connect_TimeoutConnectingToServer : DirectConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private SshOperationTimeoutException _actualException;
private Socket _clientSocket;
private Stopwatch _stopWatch;
protected override void SetupData()
{
base.SetupData();
var random = new Random();
_connectionInfo = CreateConnectionInfo(IPAddress.Loopback.ToString());
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(random.Next(50, 200));
_stopWatch = new Stopwatch();
_actualException = null;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_clientSocket != null)
{
_clientSocket.Dispose();
}
}
protected override void Act()
{
_stopWatch.Start();
try
{
Connector.Connect(_connectionInfo);
Assert.Fail();
}
catch (SshOperationTimeoutException ex)
{
_actualException = ex;
}
finally
{
_stopWatch.Stop();
}
}
[TestMethod]
public void ConnectShouldHaveThrownSshOperationTimeoutException()
{
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual(string.Format(CultureInfo.InvariantCulture, "Connection failed to establish within {0} milliseconds.", _connectionInfo.Timeout.TotalMilliseconds), _actualException.Message);
}
[TestMethod]
public void ConnectShouldHaveRespectedTimeout()
{
var errorText = string.Format("Elapsed: {0}, Timeout: {1}",
_stopWatch.ElapsedMilliseconds,
_connectionInfo.Timeout.TotalMilliseconds);
Assert.IsTrue(_stopWatch.ElapsedMilliseconds >= _connectionInfo.Timeout.TotalMilliseconds, errorText);
Assert.IsTrue(_stopWatch.ElapsedMilliseconds < (_connectionInfo.Timeout.TotalMilliseconds + 100), errorText);
}
[TestMethod]
public void ClientSocketShouldHaveBeenDisposed()
{
try
{
_clientSocket.Receive(new byte[0]);
Assert.Fail();
}
catch (ObjectDisposedException)
{
}
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,35 @@
using Moq;
using Renci.SshNet.Connection;
using Renci.SshNet.Tests.Common;
namespace Renci.SshNet.Tests.Classes.Connection
{
public abstract class HttpConnectorTestBase : TripleATestBase
{
internal Mock<ISocketFactory> SocketFactoryMock { get; private set; }
internal HttpConnector Connector { get; private set; }
internal SocketFactory SocketFactory { get; private set; }
protected virtual void CreateMocks()
{
SocketFactoryMock = new Mock<ISocketFactory>(MockBehavior.Strict);
}
protected virtual void SetupData()
{
Connector = new HttpConnector(SocketFactoryMock.Object);
SocketFactory = new SocketFactory();
}
protected virtual void SetupMocks()
{
}
protected sealed override void Arrange()
{
CreateMocks();
SetupData();
SetupMocks();
}
}
}
@@ -0,0 +1,111 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class HttpConnectorTest_Connect_ConnectionToProxyRefused : HttpConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private SocketException _actualException;
private Socket _clientSocket;
private Stopwatch _stopWatch;
protected override void SetupData()
{
base.SetupData();
_connectionInfo = new ConnectionInfo(IPAddress.Loopback.ToString(),
777,
"user",
ProxyTypes.Http,
IPAddress.Loopback.ToString(),
8122,
"proxyUser",
"proxyPwd",
new KeyboardInteractiveAuthenticationMethod("user"));
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(5000);
_stopWatch = new Stopwatch();
_actualException = null;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_clientSocket != null)
{
_clientSocket.Dispose();
}
}
protected override void Act()
{
_stopWatch.Start();
try
{
Connector.Connect(_connectionInfo);
Assert.Fail();
}
catch (SocketException ex)
{
_actualException = ex;
}
finally
{
_stopWatch.Stop();
}
}
[TestMethod]
public void ConnectShouldHaveThrownSocketException()
{
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual(SocketError.ConnectionRefused, _actualException.SocketErrorCode);
}
[TestMethod]
public void ConnectShouldHaveRespectedTimeout()
{
var errorText = string.Format("Elapsed: {0}, Timeout: {1}",
_stopWatch.ElapsedMilliseconds,
_connectionInfo.Timeout.TotalMilliseconds);
Assert.IsTrue(_stopWatch.ElapsedMilliseconds < _connectionInfo.Timeout.TotalMilliseconds, errorText);
}
[TestMethod]
public void ClientSocketShouldHaveBeenDisposed()
{
try
{
_clientSocket.Receive(new byte[0]);
Assert.Fail();
}
catch (ObjectDisposedException)
{
}
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,115 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using Renci.SshNet.Tests.Common;
using System;
using System.Net;
using System.Net.Sockets;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class HttpConnectorTest_Connect_ProxyClosesConnectionBeforeStatusLineIsSent : HttpConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private AsyncSocketListener _proxyServer;
private Socket _clientSocket;
private bool _disconnected;
private ProxyException _actualException;
protected override void SetupData()
{
base.SetupData();
_connectionInfo = new ConnectionInfo(IPAddress.Loopback.ToString(),
777,
"user",
ProxyTypes.Http,
IPAddress.Loopback.ToString(),
8122,
"proxyUser",
"proxyPwd",
new KeyboardInteractiveAuthenticationMethod("user"));
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(100);
_actualException = null;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_proxyServer = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.ProxyPort));
_proxyServer.Disconnected += socket => _disconnected = true;
_proxyServer.BytesReceived += (bytesReceived, socket) =>
{
socket.Shutdown(SocketShutdown.Send);
};
_proxyServer.Start();
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_proxyServer != null)
{
_proxyServer.Dispose();
}
if (_clientSocket != null)
{
_clientSocket.Dispose();
}
}
protected override void Act()
{
try
{
Connector.Connect(_connectionInfo);
Assert.Fail();
}
catch (ProxyException ex)
{
_actualException = ex;
}
}
[TestMethod]
public void ConnectShouldHaveThrownProxyException()
{
Assert.IsNotNull(_actualException);
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual("HTTP response does not contain status line.", _actualException.Message);
}
[TestMethod]
public void ConnectionToProxyShouldHaveBeenShutDown()
{
Assert.IsTrue(_disconnected);
}
[TestMethod]
public void ClientSocketShouldHaveBeenDisposed()
{
try
{
_clientSocket.Receive(new byte[0]);
Assert.Fail();
}
catch (ObjectDisposedException)
{
}
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,49 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Net.Sockets;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class HttpConnectorTest_Connect_ProxyHostInvalid : HttpConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private SocketException _actualException;
protected override void SetupData()
{
base.SetupData();
_connectionInfo = new ConnectionInfo("localhost",
40,
"user",
ProxyTypes.Http,
"invalid.",
80,
"proxyUser",
"proxyPwd",
new KeyboardInteractiveAuthenticationMethod("user"));
_actualException = null;
}
protected override void Act()
{
try
{
Connector.Connect(_connectionInfo);
Assert.Fail();
}
catch (SocketException ex)
{
_actualException = ex;
}
}
[TestMethod]
public void ConnectShouldHaveThrownSocketException()
{
Assert.IsNotNull(_actualException);
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual(SocketError.HostNotFound, _actualException.SocketErrorCode);
}
}
}
@@ -0,0 +1,131 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Tests.Common;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class HttpConnectorTest_Connect_ProxyPasswordIsEmpty : HttpConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private AsyncSocketListener _proxyServer;
private bool _disconnected;
private Socket _clientSocket;
private List<byte> _bytesReceivedByProxy;
private string _expectedHttpRequest;
private Socket _actual;
protected override void SetupData()
{
base.SetupData();
_connectionInfo = new ConnectionInfo(IPAddress.Loopback.ToString(),
777,
"user",
ProxyTypes.Http,
IPAddress.Loopback.ToString(),
8122,
"proxyUser",
string.Empty,
new KeyboardInteractiveAuthenticationMethod("user"));
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(20);
_expectedHttpRequest = string.Format("CONNECT {0}:{1} HTTP/1.0{2}" +
"Proxy-Authorization: Basic cHJveHlVc2VyOg=={2}{2}",
_connectionInfo.Host,
_connectionInfo.Port.ToString(CultureInfo.InvariantCulture),
"\r\n");
_bytesReceivedByProxy = new List<byte>();
_disconnected = false;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_proxyServer = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.ProxyPort));
_proxyServer.Disconnected += (socket) => _disconnected = true;
_proxyServer.Connected += socket =>
{
socket.Send(Encoding.ASCII.GetBytes("\r\n"));
socket.Send(Encoding.ASCII.GetBytes("SSH.NET\r\n"));
socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n"));
socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n"));
socket.Send(Encoding.ASCII.GetBytes("\r\n"));
socket.Send(Encoding.ASCII.GetBytes("SSH4EVER"));
socket.Shutdown(SocketShutdown.Send);
};
_proxyServer.BytesReceived += (bytesReceived, socket) =>
{
_bytesReceivedByProxy.AddRange(bytesReceived);
};
_proxyServer.Start();
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_proxyServer != null)
{
_proxyServer.Dispose();
}
if (_clientSocket != null)
{
_clientSocket.Shutdown(SocketShutdown.Both);
_clientSocket.Close();
}
}
protected override void Act()
{
_actual = Connector.Connect(_connectionInfo);
}
[TestMethod]
public void ProxyShouldHaveReceivedExpectedHttpRequest()
{
Assert.AreEqual(_expectedHttpRequest, Encoding.ASCII.GetString(_bytesReceivedByProxy.ToArray()));
}
[TestMethod]
public void ConnectShouldReturnSocketCreatedUsingSocketFactory()
{
Assert.IsNotNull(_actual);
Assert.AreSame(_clientSocket, _actual);
}
[TestMethod]
public void OnlyHttpResponseShouldHaveBeenConsumed()
{
var buffer = new byte[8];
Assert.AreEqual(8, _actual.Available);
Assert.AreEqual(8, _actual.Receive(buffer));
Assert.AreEqual("SSH4EVER", Encoding.ASCII.GetString(buffer));
Assert.AreEqual(0, _actual.Receive(buffer));
}
[TestMethod]
public void ClientSocketShouldBeConnected()
{
Assert.IsFalse(_disconnected);
Assert.IsTrue(_actual.Connected);
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,131 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Tests.Common;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class HttpConnectorTest_Connect_ProxyPasswordIsNull : HttpConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private AsyncSocketListener _proxyServer;
private bool _disconnected;
private Socket _clientSocket;
private List<byte> _bytesReceivedByProxy;
private string _expectedHttpRequest;
private Socket _actual;
protected override void SetupData()
{
base.SetupData();
_connectionInfo = new ConnectionInfo(IPAddress.Loopback.ToString(),
777,
"user",
ProxyTypes.Http,
IPAddress.Loopback.ToString(),
8122,
"proxyUser",
null,
new KeyboardInteractiveAuthenticationMethod("user"));
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(20);
_expectedHttpRequest = string.Format("CONNECT {0}:{1} HTTP/1.0{2}" +
"Proxy-Authorization: Basic cHJveHlVc2VyOg=={2}{2}",
_connectionInfo.Host,
_connectionInfo.Port.ToString(CultureInfo.InvariantCulture),
"\r\n");
_bytesReceivedByProxy = new List<byte>();
_disconnected = false;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_proxyServer = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.ProxyPort));
_proxyServer.Disconnected += (socket) => _disconnected = true;
_proxyServer.Connected += socket =>
{
socket.Send(Encoding.ASCII.GetBytes("\r\n"));
socket.Send(Encoding.ASCII.GetBytes("SSH.NET\r\n"));
socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n"));
socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n"));
socket.Send(Encoding.ASCII.GetBytes("\r\n"));
socket.Send(Encoding.ASCII.GetBytes("SSH4EVER"));
socket.Shutdown(SocketShutdown.Send);
};
_proxyServer.BytesReceived += (bytesReceived, socket) =>
{
_bytesReceivedByProxy.AddRange(bytesReceived);
};
_proxyServer.Start();
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_proxyServer != null)
{
_proxyServer.Dispose();
}
if (_clientSocket != null)
{
_clientSocket.Shutdown(SocketShutdown.Both);
_clientSocket.Close();
}
}
protected override void Act()
{
_actual = Connector.Connect(_connectionInfo);
}
[TestMethod]
public void ProxyShouldHaveReceivedExpectedHttpRequest()
{
Assert.AreEqual(_expectedHttpRequest, Encoding.ASCII.GetString(_bytesReceivedByProxy.ToArray()));
}
[TestMethod]
public void ConnectShouldReturnSocketCreatedUsingSocketFactory()
{
Assert.IsNotNull(_actual);
Assert.AreSame(_clientSocket, _actual);
}
[TestMethod]
public void OnlyHttpResponseShouldHaveBeenConsumed()
{
var buffer = new byte[8];
Assert.AreEqual(8, _actual.Available);
Assert.AreEqual(8, _actual.Receive(buffer));
Assert.AreEqual("SSH4EVER", Encoding.ASCII.GetString(buffer));
Assert.AreEqual(0, _actual.Receive(buffer));
}
[TestMethod]
public void ClientSocketShouldBeConnected()
{
Assert.IsFalse(_disconnected);
Assert.IsTrue(_actual.Connected);
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,120 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using Renci.SshNet.Tests.Common;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class HttpConnectorTest_Connect_ProxyResponseDoesNotContainHttpStatusLine : HttpConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private AsyncSocketListener _proxyServer;
private Socket _clientSocket;
private List<byte> _bytesReceivedByProxy;
private bool _disconnected;
private ProxyException _actualException;
protected override void SetupData()
{
base.SetupData();
_connectionInfo = new ConnectionInfo(IPAddress.Loopback.ToString(),
777,
"user",
ProxyTypes.Http,
IPAddress.Loopback.ToString(),
8122,
"proxyUser",
"proxyPwd",
new KeyboardInteractiveAuthenticationMethod("user"));
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(100);
_bytesReceivedByProxy = new List<byte>();
_actualException = null;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_proxyServer = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.ProxyPort));
_proxyServer.Disconnected += socket => _disconnected = true;
_proxyServer.BytesReceived += (bytesReceived, socket) =>
{
if (_bytesReceivedByProxy.Count == 0)
{
socket.Send(Encoding.ASCII.GetBytes("Whatever\r\n"));
socket.Shutdown(SocketShutdown.Send);
}
_bytesReceivedByProxy.AddRange(bytesReceived);
};
_proxyServer.Start();
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_proxyServer != null)
{
_proxyServer.Dispose();
}
}
protected override void Act()
{
try
{
Connector.Connect(_connectionInfo);
Assert.Fail();
}
catch (ProxyException ex)
{
_actualException = ex;
}
}
[TestMethod]
public void ConnectShouldHaveThrownProxyException()
{
Assert.IsNotNull(_actualException);
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual("HTTP response does not contain status line.", _actualException.Message);
}
[TestMethod]
public void ConnectionToProxyShouldHaveBeenShutDown()
{
Assert.IsTrue(_disconnected);
}
[TestMethod]
public void ClientSocketShouldHaveBeenDisposed()
{
try
{
_clientSocket.Receive(new byte[0]);
Assert.Fail();
}
catch (ObjectDisposedException)
{
}
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,135 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Tests.Common;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class HttpConnectorTest_Connect_ProxyResponseStatusIs200_ExtraTextBeforeStatusLine : HttpConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private AsyncSocketListener _proxyServer;
private bool _disconnected;
private Socket _clientSocket;
private List<byte> _bytesReceivedByProxy;
private string _expectedHttpRequest;
private Socket _actual;
protected override void SetupData()
{
base.SetupData();
_connectionInfo = new ConnectionInfo(IPAddress.Loopback.ToString(),
777,
"user",
ProxyTypes.Http,
IPAddress.Loopback.ToString(),
8122,
"proxyUser",
"proxyPwd",
new KeyboardInteractiveAuthenticationMethod("user"));
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(20);
_expectedHttpRequest = string.Format("CONNECT {0}:{1} HTTP/1.0{2}" +
"Proxy-Authorization: Basic cHJveHlVc2VyOnByb3h5UHdk{2}{2}",
_connectionInfo.Host,
_connectionInfo.Port.ToString(CultureInfo.InvariantCulture),
"\r\n");
_bytesReceivedByProxy = new List<byte>();
_disconnected = false;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_proxyServer = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.ProxyPort));
_proxyServer.Disconnected += (socket) => _disconnected = true;
_proxyServer.BytesReceived += (bytesReceived, socket) =>
{
_bytesReceivedByProxy.AddRange(bytesReceived);
// Only send response back after we've received the complete CONNECT request
// as we want to make sure HttpConnector is not waiting for any data before
// it sends the CONNECT request
if (_bytesReceivedByProxy.Count == _expectedHttpRequest.Length)
{
socket.Send(Encoding.ASCII.GetBytes("\r\n"));
socket.Send(Encoding.ASCII.GetBytes("SSH.NET\r\n"));
socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n"));
socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n"));
socket.Send(Encoding.ASCII.GetBytes("\r\n"));
socket.Send(Encoding.ASCII.GetBytes("SSH4EVER"));
socket.Shutdown(SocketShutdown.Send);
}
};
_proxyServer.Start();
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_proxyServer != null)
{
_proxyServer.Dispose();
}
if (_clientSocket != null)
{
_clientSocket.Shutdown(SocketShutdown.Both);
_clientSocket.Close();
}
}
protected override void Act()
{
_actual = Connector.Connect(_connectionInfo);
}
[TestMethod]
public void ProxyShouldHaveReceivedExpectedHttpRequest()
{
Assert.AreEqual(_expectedHttpRequest, Encoding.ASCII.GetString(_bytesReceivedByProxy.ToArray()));
}
[TestMethod]
public void ConnectShouldReturnSocketCreatedUsingSocketFactory()
{
Assert.IsNotNull(_actual);
Assert.AreSame(_clientSocket, _actual);
}
[TestMethod]
public void OnlyHttpResponseShouldHaveBeenConsumed()
{
var buffer = new byte[8];
Assert.AreEqual(8, _actual.Available);
Assert.AreEqual(8, _actual.Receive(buffer));
Assert.AreEqual("SSH4EVER", Encoding.ASCII.GetString(buffer));
Assert.AreEqual(0, _actual.Receive(buffer));
}
[TestMethod]
public void ClientSocketShouldBeConnected()
{
Assert.IsFalse(_disconnected);
Assert.IsTrue(_actual.Connected);
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,135 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Tests.Common;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class HttpConnectorTest_Connect_ProxyResponseStatusIs200_HeadersAndContent : HttpConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private AsyncSocketListener _proxyServer;
private bool _disconnected;
private Socket _clientSocket;
private List<byte> _bytesReceivedByProxy;
private string _expectedHttpRequest;
private Socket _actual;
protected override void SetupData()
{
base.SetupData();
_connectionInfo = new ConnectionInfo(IPAddress.Loopback.ToString(),
777,
"user",
ProxyTypes.Http,
IPAddress.Loopback.ToString(),
8122,
"proxyUser",
"proxyPwd",
new KeyboardInteractiveAuthenticationMethod("user"));
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(20);
_expectedHttpRequest = string.Format("CONNECT {0}:{1} HTTP/1.0{2}" +
"Proxy-Authorization: Basic cHJveHlVc2VyOnByb3h5UHdk{2}{2}",
_connectionInfo.Host,
_connectionInfo.Port.ToString(CultureInfo.InvariantCulture),
"\r\n");
_bytesReceivedByProxy = new List<byte>();
_disconnected = false;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_proxyServer = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.ProxyPort));
_proxyServer.Disconnected += (socket) => _disconnected = true;
_proxyServer.BytesReceived += (bytesReceived, socket) =>
{
_bytesReceivedByProxy.AddRange(bytesReceived);
// Only send response back after we've received the complete CONNECT request
// as we want to make sure HttpConnector is not waiting for any data before
// it sends the CONNECT request
if (_bytesReceivedByProxy.Count == _expectedHttpRequest.Length)
{
socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n"));
socket.Send(Encoding.ASCII.GetBytes("Content-Length: 10\r\n"));
socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n"));
socket.Send(Encoding.ASCII.GetBytes("\r\n"));
socket.Send(Encoding.ASCII.GetBytes("TEEN_BYTES"));
socket.Send(Encoding.ASCII.GetBytes("!666!"));
socket.Shutdown(SocketShutdown.Send);
}
};
_proxyServer.Start();
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_proxyServer != null)
{
_proxyServer.Dispose();
}
if (_clientSocket != null)
{
_clientSocket.Shutdown(SocketShutdown.Both);
_clientSocket.Close();
}
}
protected override void Act()
{
_actual = Connector.Connect(_connectionInfo);
}
[TestMethod]
public void ProxyShouldHaveReceivedExpectedHttpRequest()
{
Assert.AreEqual(_expectedHttpRequest, Encoding.ASCII.GetString(_bytesReceivedByProxy.ToArray()));
}
[TestMethod]
public void ConnectShouldReturnSocketCreatedUsingSocketFactory()
{
Assert.IsNotNull(_actual);
Assert.AreSame(_clientSocket, _actual);
}
[TestMethod]
public void OnlyHttpResponseShouldHaveBeenConsumed()
{
var buffer = new byte[5];
Assert.AreEqual(5, _actual.Available);
Assert.AreEqual(5, _actual.Receive(buffer));
Assert.AreEqual("!666!", Encoding.ASCII.GetString(buffer));
Assert.AreEqual(0, _actual.Receive(buffer));
}
[TestMethod]
public void ClientSocketShouldBeConnected()
{
Assert.IsFalse(_disconnected);
Assert.IsTrue(_actual.Connected);
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,133 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Tests.Common;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class HttpConnectorTest_Connect_ProxyResponseStatusIs200_OnlyHeaders : HttpConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private AsyncSocketListener _proxyServer;
private bool _disconnected;
private Socket _clientSocket;
private List<byte> _bytesReceivedByProxy;
private string _expectedHttpRequest;
private Socket _actual;
protected override void SetupData()
{
base.SetupData();
_connectionInfo = new ConnectionInfo(IPAddress.Loopback.ToString(),
777,
"user",
ProxyTypes.Http,
IPAddress.Loopback.ToString(),
8122,
"proxyUser",
"proxyPwd",
new KeyboardInteractiveAuthenticationMethod("user"));
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(20);
_expectedHttpRequest = string.Format("CONNECT {0}:{1} HTTP/1.0{2}" +
"Proxy-Authorization: Basic cHJveHlVc2VyOnByb3h5UHdk{2}{2}",
_connectionInfo.Host,
_connectionInfo.Port.ToString(CultureInfo.InvariantCulture),
"\r\n");
_bytesReceivedByProxy = new List<byte>();
_disconnected = false;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_proxyServer = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.ProxyPort));
_proxyServer.Disconnected += (socket) => _disconnected = true;
_proxyServer.BytesReceived += (bytesReceived, socket) =>
{
_bytesReceivedByProxy.AddRange(bytesReceived);
// Only send response back after we've received the complete CONNECT request
// as we want to make sure HttpConnector is not waiting for any data before
// it sends the CONNECT request
if (_bytesReceivedByProxy.Count == _expectedHttpRequest.Length)
{
socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n"));
socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n"));
socket.Send(Encoding.ASCII.GetBytes("\r\n"));
socket.Send(Encoding.ASCII.GetBytes("SSH4EVER"));
socket.Shutdown(SocketShutdown.Send);
}
};
_proxyServer.Start();
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_proxyServer != null)
{
_proxyServer.Dispose();
}
if (_clientSocket != null)
{
_clientSocket.Shutdown(SocketShutdown.Both);
_clientSocket.Close();
}
}
protected override void Act()
{
_actual = Connector.Connect(_connectionInfo);
}
[TestMethod]
public void ProxyShouldHaveReceivedExpectedHttpRequest()
{
Assert.AreEqual(_expectedHttpRequest, Encoding.ASCII.GetString(_bytesReceivedByProxy.ToArray()));
}
[TestMethod]
public void ConnectShouldReturnSocketCreatedUsingSocketFactory()
{
Assert.IsNotNull(_actual);
Assert.AreSame(_clientSocket, _actual);
}
[TestMethod]
public void OnlyHttpResponseShouldHaveBeenConsumed()
{
var buffer = new byte[8];
Assert.AreEqual(8, _actual.Available);
Assert.AreEqual(8, _actual.Receive(buffer));
Assert.AreEqual("SSH4EVER", Encoding.ASCII.GetString(buffer));
Assert.AreEqual(0, _actual.Receive(buffer));
}
[TestMethod]
public void ClientSocketShouldBeConnected()
{
Assert.IsFalse(_disconnected);
Assert.IsTrue(_actual.Connected);
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,120 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using Renci.SshNet.Tests.Common;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class HttpConnectorTest_Connect_ProxyResponseStatusIsNot200 : HttpConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private AsyncSocketListener _proxyServer;
private Socket _clientSocket;
private List<byte> _bytesReceivedByProxy;
private bool _disconnected;
private ProxyException _actualException;
protected override void SetupData()
{
base.SetupData();
_connectionInfo = new ConnectionInfo(IPAddress.Loopback.ToString(),
777,
"user",
ProxyTypes.Http,
IPAddress.Loopback.ToString(),
8122,
"proxyUser",
"proxyPwd",
new KeyboardInteractiveAuthenticationMethod("user"));
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(100);
_bytesReceivedByProxy = new List<byte>();
_actualException = null;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_proxyServer = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.ProxyPort));
_proxyServer.Disconnected += (socket) => _disconnected = true;
_proxyServer.BytesReceived += (bytesReceived, socket) =>
{
if (_bytesReceivedByProxy.Count == 0)
{
socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 404 I searched everywhere, really...\r\n"));
socket.Shutdown(SocketShutdown.Send);
}
_bytesReceivedByProxy.AddRange(bytesReceived);
};
_proxyServer.Start();
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_proxyServer != null)
{
_proxyServer.Dispose();
}
}
protected override void Act()
{
try
{
Connector.Connect(_connectionInfo);
Assert.Fail();
}
catch (ProxyException ex)
{
_actualException = ex;
}
}
[TestMethod]
public void ConnectShouldHaveThrownProxyException()
{
Assert.IsNotNull(_actualException);
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual("HTTP: Status code 404, \"I searched everywhere, really...\"", _actualException.Message);
}
[TestMethod]
public void ConnectionToProxyShouldHaveBeenShutDown()
{
Assert.IsTrue(_disconnected);
}
[TestMethod]
public void ClientSocketShouldHaveBeenDisposed()
{
try
{
_clientSocket.Receive(new byte[0]);
Assert.Fail();
}
catch (ObjectDisposedException)
{
}
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,132 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Tests.Common;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class HttpConnectorTest_Connect_ProxyUserNameIsEmpty : HttpConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private AsyncSocketListener _proxyServer;
private bool _disconnected;
private Socket _clientSocket;
private List<byte> _bytesReceivedByProxy;
private string _expectedHttpRequest;
private Socket _actual;
protected override void SetupData()
{
base.SetupData();
_connectionInfo = new ConnectionInfo(IPAddress.Loopback.ToString(),
777,
"user",
ProxyTypes.Http,
IPAddress.Loopback.ToString(),
8122,
string.Empty,
"proxyPwd",
new KeyboardInteractiveAuthenticationMethod("user"));
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(20);
_expectedHttpRequest = string.Format("CONNECT {0}:{1} HTTP/1.0{2}{2}",
_connectionInfo.Host,
_connectionInfo.Port.ToString(CultureInfo.InvariantCulture),
"\r\n");
_bytesReceivedByProxy = new List<byte>();
_disconnected = false;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_proxyServer = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.ProxyPort));
_proxyServer.Disconnected += (socket) => _disconnected = true;
_proxyServer.BytesReceived += (bytesReceived, socket) =>
{
_bytesReceivedByProxy.AddRange(bytesReceived);
// Only send response back after we've received the complete CONNECT request
// as we want to make sure HttpConnector is not waiting for any data before
// it sends the CONNECT request
if (_bytesReceivedByProxy.Count == _expectedHttpRequest.Length)
{
socket.Send(Encoding.ASCII.GetBytes("\r\n"));
socket.Send(Encoding.ASCII.GetBytes("SSH.NET\r\n"));
socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n"));
socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n"));
socket.Send(Encoding.ASCII.GetBytes("\r\n"));
socket.Send(Encoding.ASCII.GetBytes("SSH4EVER"));
}
};
_proxyServer.Start();
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_clientSocket != null)
{
_clientSocket.Shutdown(SocketShutdown.Send);
_clientSocket.Close();
}
if (_proxyServer != null)
{
_proxyServer.Dispose();
}
}
protected override void Act()
{
_actual = Connector.Connect(_connectionInfo);
}
[TestMethod]
public void ProxyShouldHaveReceivedExpectedHttpRequest()
{
Assert.AreEqual(_expectedHttpRequest, Encoding.ASCII.GetString(_bytesReceivedByProxy.ToArray()));
}
[TestMethod]
public void ConnectShouldReturnSocketCreatedUsingSocketFactory()
{
Assert.IsNotNull(_actual);
Assert.AreSame(_clientSocket, _actual);
}
[TestMethod]
public void OnlyHttpResponseShouldHaveBeenConsumed()
{
var buffer = new byte[8];
Assert.AreEqual(8, _actual.Available);
Assert.AreEqual(8, _actual.Receive(buffer));
Assert.AreEqual("SSH4EVER", Encoding.ASCII.GetString(buffer));
}
[TestMethod]
public void ClientSocketShouldBeConnected()
{
Assert.IsFalse(_disconnected);
Assert.IsTrue(_actual.Connected);
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,128 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Tests.Common;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class HttpConnectorTest_Connect_ProxyUserNameIsNotNullAndNotEmpty : HttpConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private AsyncSocketListener _proxyServer;
private bool _disconnected;
private Socket _clientSocket;
private List<byte> _bytesReceivedByProxy;
private string _expectedHttpRequest;
private Socket _actual;
protected override void SetupData()
{
base.SetupData();
_connectionInfo = new ConnectionInfo(IPAddress.Loopback.ToString(),
777,
"user",
ProxyTypes.Http,
IPAddress.Loopback.ToString(),
8122,
"user",
"pwd",
new KeyboardInteractiveAuthenticationMethod("user"));
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(20);
_expectedHttpRequest = string.Format("CONNECT {0}:{1} HTTP/1.0{2}" +
"Proxy-Authorization: Basic dXNlcjpwd2Q={2}{2}",
_connectionInfo.Host,
_connectionInfo.Port.ToString(CultureInfo.InvariantCulture),
"\r\n");
_bytesReceivedByProxy = new List<byte>();
_disconnected = false;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_proxyServer = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.ProxyPort));
_proxyServer.Connected += (socket) =>
{
socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n"));
socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n"));
socket.Send(Encoding.ASCII.GetBytes("\r\n"));
socket.Send(Encoding.ASCII.GetBytes("SSH4EVER"));
};
_proxyServer.Disconnected += (socket) => _disconnected = true;
_proxyServer.BytesReceived += (bytesReceived, socket) =>
{
_bytesReceivedByProxy.AddRange(bytesReceived);
};
_proxyServer.Start();
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_proxyServer != null)
{
_proxyServer.Dispose();
}
if (_clientSocket != null)
{
_clientSocket.Shutdown(SocketShutdown.Both);
_clientSocket.Close();
}
}
protected override void Act()
{
_actual = Connector.Connect(_connectionInfo);
}
[TestMethod]
public void ProxyShouldHaveReceivedExpectedHttpRequest()
{
Assert.AreEqual(_expectedHttpRequest, Encoding.ASCII.GetString(_bytesReceivedByProxy.ToArray()));
}
[TestMethod]
public void ConnectShouldReturnSocketCreatedUsingSocketFactory()
{
Assert.IsNotNull(_actual);
Assert.AreSame(_clientSocket, _actual);
}
[TestMethod]
public void OnlyHttpResponseShouldHaveBeenConsumed()
{
var buffer = new byte[8];
Assert.AreEqual(8, _actual.Available);
Assert.AreEqual(8, _actual.Receive(buffer));
Assert.AreEqual("SSH4EVER", Encoding.ASCII.GetString(buffer));
}
[TestMethod]
public void ClientSocketShouldBeConnected()
{
Assert.IsFalse(_disconnected);
Assert.IsTrue(_actual.Connected);
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,132 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Tests.Common;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class HttpConnectorTest_Connect_ProxyUserNameIsNull : HttpConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private AsyncSocketListener _proxyServer;
private bool _disconnected;
private Socket _clientSocket;
private List<byte> _bytesReceivedByProxy;
private string _expectedHttpRequest;
private Socket _actual;
protected override void SetupData()
{
base.SetupData();
_connectionInfo = new ConnectionInfo(IPAddress.Loopback.ToString(),
777,
"user",
ProxyTypes.Http,
IPAddress.Loopback.ToString(),
8122,
null,
"proxyPwd",
new KeyboardInteractiveAuthenticationMethod("user"));
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(20);
_expectedHttpRequest = string.Format("CONNECT {0}:{1} HTTP/1.0{2}{2}",
_connectionInfo.Host,
_connectionInfo.Port.ToString(CultureInfo.InvariantCulture),
"\r\n");
_bytesReceivedByProxy = new List<byte>();
_disconnected = false;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_proxyServer = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.ProxyPort));
_proxyServer.Disconnected += (socket) => _disconnected = true;
_proxyServer.BytesReceived += (bytesReceived, socket) =>
{
_bytesReceivedByProxy.AddRange(bytesReceived);
// Only send response back after we've received the complete CONNECT request
// as we want to make sure HttpConnector is not waiting for any data before
// it sends the CONNECT request
if (_bytesReceivedByProxy.Count == _expectedHttpRequest.Length)
{
socket.Send(Encoding.ASCII.GetBytes("\r\n"));
socket.Send(Encoding.ASCII.GetBytes("SSH.NET\r\n"));
socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n"));
socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n"));
socket.Send(Encoding.ASCII.GetBytes("\r\n"));
socket.Send(Encoding.ASCII.GetBytes("SSH4EVER"));
}
};
_proxyServer.Start();
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_clientSocket != null)
{
_clientSocket.Shutdown(SocketShutdown.Send);
_clientSocket.Close();
}
if (_proxyServer != null)
{
_proxyServer.Dispose();
}
}
protected override void Act()
{
_actual = Connector.Connect(_connectionInfo);
}
[TestMethod]
public void ProxyShouldHaveReceivedExpectedHttpRequest()
{
Assert.AreEqual(_expectedHttpRequest, Encoding.ASCII.GetString(_bytesReceivedByProxy.ToArray()));
}
[TestMethod]
public void ConnectShouldReturnSocketCreatedUsingSocketFactory()
{
Assert.IsNotNull(_actual);
Assert.AreSame(_clientSocket, _actual);
}
[TestMethod]
public void OnlyHttpResponseShouldHaveBeenConsumed()
{
var buffer = new byte[8];
Assert.AreEqual(8, _actual.Available);
Assert.AreEqual(8, _actual.Receive(buffer));
Assert.AreEqual("SSH4EVER", Encoding.ASCII.GetString(buffer));
}
[TestMethod]
public void ClientSocketShouldBeConnected()
{
Assert.IsFalse(_disconnected);
Assert.IsTrue(_actual.Connected);
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,115 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using System;
using System.Diagnostics;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class HttpConnectorTest_Connect_TimeoutConnectingToProxy : HttpConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private SshOperationTimeoutException _actualException;
private Socket _clientSocket;
private Stopwatch _stopWatch;
protected override void SetupData()
{
base.SetupData();
var random = new Random();
_connectionInfo = new ConnectionInfo(IPAddress.Loopback.ToString(),
777,
"user",
ProxyTypes.Http,
IPAddress.Loopback.ToString(),
8122,
"proxyUser",
"proxyPwd",
new KeyboardInteractiveAuthenticationMethod("user"));
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(random.Next(50, 200));
_stopWatch = new Stopwatch();
_actualException = null;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_clientSocket != null)
{
_clientSocket.Dispose();
}
}
protected override void Act()
{
_stopWatch.Start();
try
{
Connector.Connect(_connectionInfo);
Assert.Fail();
}
catch (SshOperationTimeoutException ex)
{
_actualException = ex;
}
finally
{
_stopWatch.Stop();
}
}
[TestMethod]
public void ConnectShouldHaveThrownSshOperationTimeoutException()
{
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual(string.Format(CultureInfo.InvariantCulture, "Connection failed to establish within {0} milliseconds.", _connectionInfo.Timeout.TotalMilliseconds), _actualException.Message);
}
[TestMethod]
public void ConnectShouldHaveRespectedTimeout()
{
var errorText = string.Format("Elapsed: {0}, Timeout: {1}",
_stopWatch.ElapsedMilliseconds,
_connectionInfo.Timeout.TotalMilliseconds);
Assert.IsTrue(_stopWatch.ElapsedMilliseconds >= _connectionInfo.Timeout.TotalMilliseconds, errorText);
Assert.IsTrue(_stopWatch.ElapsedMilliseconds < (_connectionInfo.Timeout.TotalMilliseconds + 100), errorText);
}
[TestMethod]
public void ClientSocketShouldHaveBeenDisposed()
{
try
{
_clientSocket.Receive(new byte[0]);
Assert.Fail();
}
catch (ObjectDisposedException)
{
}
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,169 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using Renci.SshNet.Connection;
using Renci.SshNet.Tests.Common;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class HttpConnectorTest_Connect_TimeoutReadingHttpContent : HttpConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private SshOperationTimeoutException _actualException;
private Socket _clientSocket;
private AsyncSocketListener _proxyServer;
private List<byte> _bytesReceivedByProxy;
private string _expectedHttpRequest;
private Stopwatch _stopWatch;
private AsyncSocketListener _server;
private bool _disconnected;
protected override void SetupData()
{
base.SetupData();
var random = new Random();
_connectionInfo = new ConnectionInfo(IPAddress.Loopback.ToString(),
777,
"user",
ProxyTypes.Http,
IPAddress.Loopback.ToString(),
8122,
"proxyUser",
"proxyPwd",
new KeyboardInteractiveAuthenticationMethod("user"));
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(random.Next(50, 200));
_expectedHttpRequest = string.Format("CONNECT {0}:{1} HTTP/1.0{2}" +
"Proxy-Authorization: Basic cHJveHlVc2VyOnByb3h5UHdk{2}{2}",
_connectionInfo.Host,
_connectionInfo.Port.ToString(CultureInfo.InvariantCulture),
"\r\n");
_bytesReceivedByProxy = new List<byte>();
_stopWatch = new Stopwatch();
_actualException = null;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_proxyServer = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.ProxyPort));
_proxyServer.Disconnected += (socket) => _disconnected = true;
_proxyServer.BytesReceived += (bytesReceived, socket) =>
{
_bytesReceivedByProxy.AddRange(bytesReceived);
// Force a timeout by sending less content than indicated by Content-Length header
if (_bytesReceivedByProxy.Count == _expectedHttpRequest.Length)
{
socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n"));
socket.Send(Encoding.ASCII.GetBytes("Content-Length: 10\r\n"));
socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n"));
socket.Send(Encoding.ASCII.GetBytes("\r\n"));
socket.Send(Encoding.ASCII.GetBytes("TOO_FEW"));
}
};
_proxyServer.Start();
_server = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.Port));
_server.Start();
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_server != null)
{
_server.Dispose();
}
if (_proxyServer != null)
{
_proxyServer.Dispose();
}
}
protected override void Act()
{
_stopWatch.Start();
try
{
Connector.Connect(_connectionInfo);
Assert.Fail();
}
catch (SshOperationTimeoutException ex)
{
_actualException = ex;
}
finally
{
_stopWatch.Stop();
}
}
[TestMethod]
public void ConnectShouldHaveThrownSshOperationTimeoutException()
{
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual(string.Format(CultureInfo.InvariantCulture, "Socket read operation has timed out after {0:F0} milliseconds.", _connectionInfo.Timeout.TotalMilliseconds), _actualException.Message);
}
[TestMethod]
public void ProxyShouldHaveReceivedExpectedHttpRequest()
{
Assert.AreEqual(_expectedHttpRequest, Encoding.ASCII.GetString(_bytesReceivedByProxy.ToArray()));
}
[TestMethod]
public void ConnectShouldHaveRespectedTimeout()
{
var errorText = string.Format("Elapsed: {0}, Timeout: {1}",
_stopWatch.ElapsedMilliseconds,
_connectionInfo.Timeout.TotalMilliseconds);
Assert.IsTrue(_stopWatch.ElapsedMilliseconds >= _connectionInfo.Timeout.TotalMilliseconds, errorText);
Assert.IsTrue(_stopWatch.ElapsedMilliseconds < (_connectionInfo.Timeout.TotalMilliseconds + 100), errorText);
}
[TestMethod]
public void ClientSocketShouldNotBeConnected()
{
Assert.IsTrue(_disconnected);
Assert.IsFalse(_clientSocket.Connected);
}
[TestMethod]
public void ClientSocketShouldHaveBeenDisposed()
{
try
{
_clientSocket.Receive(new byte[0]);
Assert.Fail();
}
catch (ObjectDisposedException)
{
}
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,139 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using Renci.SshNet.Connection;
using Renci.SshNet.Tests.Common;
using System;
using System.Diagnostics;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class HttpConnectorTest_Connect_TimeoutReadingStatusLine : HttpConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private SshOperationTimeoutException _actualException;
private Socket _clientSocket;
private AsyncSocketListener _proxyServer;
private Stopwatch _stopWatch;
private AsyncSocketListener _server;
private bool _disconnected;
protected override void SetupData()
{
base.SetupData();
var random = new Random();
_connectionInfo = new ConnectionInfo(IPAddress.Loopback.ToString(),
777,
"user",
ProxyTypes.Http,
IPAddress.Loopback.ToString(),
8122,
"proxyUser",
"proxyPwd",
new KeyboardInteractiveAuthenticationMethod("user"));
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(random.Next(50, 200));
_stopWatch = new Stopwatch();
_actualException = null;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_proxyServer = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.ProxyPort));
_proxyServer.Disconnected += (socket) => _disconnected = true;
_proxyServer.Start();
_server = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.Port));
_server.Start();
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_server != null)
{
_server.Dispose();
}
if (_proxyServer != null)
{
_proxyServer.Dispose();
}
}
protected override void Act()
{
_stopWatch.Start();
try
{
Connector.Connect(_connectionInfo);
Assert.Fail();
}
catch (SshOperationTimeoutException ex)
{
_actualException = ex;
}
finally
{
_stopWatch.Stop();
}
}
[TestMethod]
public void ConnectShouldHaveThrownSshOperationTimeoutException()
{
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual(string.Format(CultureInfo.InvariantCulture, "Socket read operation has timed out after {0:F0} milliseconds.", _connectionInfo.Timeout.TotalMilliseconds), _actualException.Message);
}
[TestMethod]
public void ConnectShouldHaveRespectedTimeout()
{
var errorText = string.Format("Elapsed: {0}, Timeout: {1}",
_stopWatch.ElapsedMilliseconds,
_connectionInfo.Timeout.TotalMilliseconds);
Assert.IsTrue(_stopWatch.ElapsedMilliseconds >= _connectionInfo.Timeout.TotalMilliseconds, errorText);
Assert.IsTrue(_stopWatch.ElapsedMilliseconds < (_connectionInfo.Timeout.TotalMilliseconds + 100), errorText);
}
[TestMethod]
public void ClientSocketShouldNotBeConnected()
{
Assert.IsTrue(_disconnected);
Assert.IsFalse(_clientSocket.Connected);
}
[TestMethod]
public void ClientSocketShouldHaveBeenDisposed()
{
try
{
_clientSocket.Receive(new byte[0]);
Assert.Fail();
}
catch (ObjectDisposedException)
{
}
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -55,16 +55,16 @@ namespace Renci.SshNet.Tests.Classes
_timeout = TimeSpan.FromSeconds(5);
_serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
_dataReceivedByServer = new List<byte>();
_serverIdentification = Encoding.UTF8.GetBytes("Welcome stranger!\r\n\r\nSSH-ABC2.0-OurSSHAppliance-1.4.7 Use at own risk.\uD55C\r\n!");
_serverIdentification = Encoding.UTF8.GetBytes("\r\nWelcome stranger!\r\n\r\nSSH-ABC2.0-OurSSHAppliance-1.4.7 Use at own risk.\uD55C\r\n!");
_server = new AsyncSocketListener(_serverEndPoint);
_server.Start();
_server.BytesReceived += (bytes, socket) =>
{
_dataReceivedByServer.AddRange(bytes);
socket.Send(_serverIdentification);
socket.Shutdown(SocketShutdown.Both);
};
{
_dataReceivedByServer.AddRange(bytes);
socket.Send(_serverIdentification);
socket.Shutdown(SocketShutdown.Both);
};
_server.Disconnected += (socket) => _clientDisconnected = true;
_client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
@@ -0,0 +1,49 @@
using Moq;
using Renci.SshNet.Connection;
using Renci.SshNet.Tests.Common;
using System.Net;
namespace Renci.SshNet.Tests.Classes.Connection
{
public abstract class Socks4ConnectorTestBase : TripleATestBase
{
internal Mock<ISocketFactory> SocketFactoryMock { get; private set; }
internal Socks4Connector Connector { get; private set; }
internal SocketFactory SocketFactory { get; private set; }
protected virtual void CreateMocks()
{
SocketFactoryMock = new Mock<ISocketFactory>(MockBehavior.Strict);
}
protected virtual void SetupData()
{
Connector = new Socks4Connector(SocketFactoryMock.Object);
SocketFactory = new SocketFactory();
}
protected virtual void SetupMocks()
{
}
protected sealed override void Arrange()
{
CreateMocks();
SetupData();
SetupMocks();
}
protected ConnectionInfo CreateConnectionInfo(string proxyUser, string proxyPassword)
{
return new ConnectionInfo(IPAddress.Loopback.ToString(),
777,
"user",
ProxyTypes.Socks4,
IPAddress.Loopback.ToString(),
8122,
proxyUser,
proxyPassword,
new KeyboardInteractiveAuthenticationMethod("user"));
}
}
}
@@ -0,0 +1,134 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using Renci.SshNet.Tests.Common;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class Socks4ConnectorTest_Connect_ConnectionRejectedByProxy : Socks4ConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private AsyncSocketListener _proxyServer;
private Socket _clientSocket;
private List<byte> _bytesReceivedByProxy;
private bool _disconnected;
private ProxyException _actualException;
protected override void SetupData()
{
base.SetupData();
_connectionInfo = CreateConnectionInfo("proxyUser", "proxyPwd");
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(100);
_bytesReceivedByProxy = new List<byte>();
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_actualException = null;
_proxyServer = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.ProxyPort));
_proxyServer.Disconnected += socket => _disconnected = true;
_proxyServer.BytesReceived += (bytesReceived, socket) =>
{
if (_bytesReceivedByProxy.Count == 0)
{
socket.Send(new byte[]
{
// Reply version (null byte)
0x00,
// Connection refused
0x5b
});
}
_bytesReceivedByProxy.AddRange(bytesReceived);
};
_proxyServer.Start();
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_proxyServer != null)
{
_proxyServer.Dispose();
}
if (_clientSocket != null)
{
_clientSocket.Dispose();
}
}
protected override void Act()
{
try
{
Connector.Connect(_connectionInfo);
Assert.Fail();
}
catch (ProxyException ex)
{
_actualException = ex;
}
}
[TestMethod]
public void ConnectShouldHaveThrownProxyException()
{
Assert.IsNotNull(_actualException);
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual("SOCKS4: Connection rejected.", _actualException.Message);
}
[TestMethod]
public void ConnectionToProxyShouldHaveBeenShutDown()
{
Assert.IsTrue(_disconnected);
}
[TestMethod]
public void ClientSocketShouldHaveBeenDisposed()
{
try
{
_clientSocket.Receive(new byte[0]);
Assert.Fail();
}
catch (ObjectDisposedException)
{
}
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
private static byte GetNotSupportedSocksVersion()
{
var random = new Random();
while (true)
{
var socksVersion = random.Next(1, 255);
if (socksVersion != 4)
{
return (byte) socksVersion;
}
}
}
}
}
@@ -0,0 +1,166 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using Renci.SshNet.Connection;
using Renci.SshNet.Tests.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class Socks4ConnectorTest_Connect_ConnectionSucceeded : Socks4ConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private Socket _clientSocket;
private AsyncSocketListener _proxyServer;
private List<byte> _bytesReceivedByProxy;
private bool _disconnected;
private Socket _actual;
protected override void SetupData()
{
base.SetupData();
var random = new Random();
_connectionInfo = CreateConnectionInfo("proxyUser", "proxyPwd");
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(random.Next(50, 200));
_bytesReceivedByProxy = new List<byte>();
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_actual = null;
_proxyServer = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.ProxyPort));
_proxyServer.Disconnected += socket => _disconnected = true;
_proxyServer.BytesReceived += (bytesReceived, socket) =>
{
_bytesReceivedByProxy.AddRange(bytesReceived);
if (_bytesReceivedByProxy.Count == bytesReceived.Length)
{
// Send SOCKS response
socket.Send(new byte[]
{
// Reply version (null byte)
0x00,
// Request granted
0x5a,
// Destination address port
0x01,
0xf0,
// Destination address IP
0x01,
0x02,
0x03,
0x04
});
// Send extra byte to allow us to verify that connector did not consume too much
socket.Send(new byte[]
{
0xfe
});
}
};
_proxyServer.Start();
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_proxyServer != null)
{
_proxyServer.Dispose();
}
if (_clientSocket != null)
{
_clientSocket.Dispose();
}
}
protected override void Act()
{
_actual = Connector.Connect(_connectionInfo);
}
[TestMethod]
public void ProxyShouldHaveReceivedExpectedSocksRequest()
{
var expectedSocksRequest = new byte[]
{
// SOCKS version
0x04,
// CONNECT request
0x01,
// Destination port
0x03,
0x09,
// Destination address (IPv4)
0x7f,
0x00,
0x00,
0x01,
// Proxy user
0x70,
0x72,
0x6f,
0x78,
0x79,
0x55,
0x73,
0x65,
0x72,
// Null terminator
0x00
};
var errorText = string.Format("Expected:{0}{1}{0}but was:{0}{2}",
Environment.NewLine,
PacketDump.Create(expectedSocksRequest, 2),
PacketDump.Create(_bytesReceivedByProxy, 2));
Assert.IsTrue(expectedSocksRequest.SequenceEqual(_bytesReceivedByProxy), errorText);
}
[TestMethod]
public void ConnectShouldReturnSocketCreatedUsingSocketFactory()
{
Assert.IsNotNull(_actual);
Assert.AreSame(_clientSocket, _actual);
}
[TestMethod]
public void OnlySocksResponseShouldHaveBeenConsumed()
{
var buffer = new byte[2];
Assert.AreEqual(1, _actual.Receive(buffer));
Assert.AreEqual(0xfe, buffer[0]);
}
[TestMethod]
public void ClientSocketShouldBeConnected()
{
Assert.IsFalse(_disconnected);
Assert.IsTrue(_actual.Connected);
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,102 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using System;
using System.Diagnostics;
using System.Net.Sockets;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class Socks4ConnectorTest_Connect_ConnectionToProxyRefused : Socks4ConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private SocketException _actualException;
private Socket _clientSocket;
private Stopwatch _stopWatch;
protected override void SetupData()
{
base.SetupData();
_connectionInfo = CreateConnectionInfo("proxyUser", "proxyPwd");
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(5000);
_stopWatch = new Stopwatch();
_actualException = null;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_clientSocket != null)
{
_clientSocket.Dispose();
}
}
protected override void Act()
{
_stopWatch.Start();
try
{
Connector.Connect(_connectionInfo);
Assert.Fail();
}
catch (SocketException ex)
{
_actualException = ex;
}
finally
{
_stopWatch.Stop();
}
}
[TestMethod]
public void ConnectShouldHaveThrownSocketException()
{
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual(SocketError.ConnectionRefused, _actualException.SocketErrorCode);
}
[TestMethod]
public void ConnectShouldHaveRespectedTimeout()
{
var errorText = string.Format("Elapsed: {0}, Timeout: {1}",
_stopWatch.ElapsedMilliseconds,
_connectionInfo.Timeout.TotalMilliseconds);
Assert.IsTrue(_stopWatch.ElapsedMilliseconds < _connectionInfo.Timeout.TotalMilliseconds, errorText);
}
[TestMethod]
public void ClientSocketShouldHaveBeenDisposed()
{
try
{
_clientSocket.Receive(new byte[0]);
Assert.Fail();
}
catch (ObjectDisposedException)
{
}
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,105 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using System;
using System.Diagnostics;
using System.Globalization;
using System.Net.Sockets;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class Socks4ConnectorTest_Connect_TimeoutConnectingToProxy : Socks4ConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private SshOperationTimeoutException _actualException;
private Socket _clientSocket;
private Stopwatch _stopWatch;
protected override void SetupData()
{
base.SetupData();
var random = new Random();
_connectionInfo = CreateConnectionInfo("proxyUser", "proxyPwd");
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(random.Next(50, 200));
_stopWatch = new Stopwatch();
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_actualException = null;
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_clientSocket != null)
{
_clientSocket.Dispose();
}
}
protected override void Act()
{
_stopWatch.Start();
try
{
Connector.Connect(_connectionInfo);
Assert.Fail();
}
catch (SshOperationTimeoutException ex)
{
_actualException = ex;
}
finally
{
_stopWatch.Stop();
}
}
[TestMethod]
public void ConnectShouldHaveThrownSshOperationTimeoutException()
{
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual(string.Format(CultureInfo.InvariantCulture, "Connection failed to establish within {0} milliseconds.", _connectionInfo.Timeout.TotalMilliseconds), _actualException.Message);
}
[TestMethod]
public void ConnectShouldHaveRespectedTimeout()
{
var errorText = string.Format("Elapsed: {0}, Timeout: {1}",
_stopWatch.ElapsedMilliseconds,
_connectionInfo.Timeout.TotalMilliseconds);
Assert.IsTrue(_stopWatch.ElapsedMilliseconds >= _connectionInfo.Timeout.TotalMilliseconds, errorText);
Assert.IsTrue(_stopWatch.ElapsedMilliseconds < (_connectionInfo.Timeout.TotalMilliseconds + 100), errorText);
}
[TestMethod]
public void ClientSocketShouldHaveBeenDisposed()
{
try
{
_clientSocket.Receive(new byte[0]);
Assert.Fail();
}
catch (ObjectDisposedException)
{
}
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,143 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using Renci.SshNet.Connection;
using Renci.SshNet.Tests.Common;
using System;
using System.Diagnostics;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class Socks4ConnectorTest_Connect_TimeoutReadingDestinationAddress : Socks4ConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private SshOperationTimeoutException _actualException;
private Socket _clientSocket;
private AsyncSocketListener _proxyServer;
private Stopwatch _stopWatch;
private AsyncSocketListener _server;
private bool _disconnected;
protected override void SetupData()
{
base.SetupData();
var random = new Random();
_connectionInfo = CreateConnectionInfo("proxyUser", "proxyPwd");
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(random.Next(50, 200));
_stopWatch = new Stopwatch();
_actualException = null;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_proxyServer = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.ProxyPort));
_proxyServer.Disconnected += socket => _disconnected = true;
_proxyServer.Connected += socket =>
{
socket.Send(new byte[]
{
// Reply version (null byte)
0x00,
// Request granted
0x5a,
// Incomplete destination address
0x01
});
};
_proxyServer.Start();
_server = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.Port));
_server.Start();
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_server != null)
{
_server.Dispose();
}
if (_proxyServer != null)
{
_proxyServer.Dispose();
}
}
protected override void Act()
{
_stopWatch.Start();
try
{
Connector.Connect(_connectionInfo);
Assert.Fail();
}
catch (SshOperationTimeoutException ex)
{
_actualException = ex;
}
finally
{
_stopWatch.Stop();
}
}
[TestMethod]
public void ConnectShouldHaveThrownSshOperationTimeoutException()
{
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual(string.Format(CultureInfo.InvariantCulture, "Socket read operation has timed out after {0:F0} milliseconds.", _connectionInfo.Timeout.TotalMilliseconds), _actualException.Message);
}
[TestMethod]
public void ConnectShouldHaveRespectedTimeout()
{
var errorText = string.Format("Elapsed: {0}, Timeout: {1}",
_stopWatch.ElapsedMilliseconds,
_connectionInfo.Timeout.TotalMilliseconds);
Assert.IsTrue(_stopWatch.ElapsedMilliseconds >= _connectionInfo.Timeout.TotalMilliseconds, errorText);
Assert.IsTrue(_stopWatch.ElapsedMilliseconds < (_connectionInfo.Timeout.TotalMilliseconds + 100), errorText);
}
[TestMethod]
public void ClientSocketShouldNotBeConnected()
{
Assert.IsTrue(_disconnected);
Assert.IsFalse(_clientSocket.Connected);
}
[TestMethod]
public void ClientSocketShouldHaveBeenDisposed()
{
try
{
_clientSocket.Receive(new byte[0]);
Assert.Fail();
}
catch (ObjectDisposedException)
{
}
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,139 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using Renci.SshNet.Connection;
using Renci.SshNet.Tests.Common;
using System;
using System.Diagnostics;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class Socks4ConnectorTest_Connect_TimeoutReadingReplyCode : Socks4ConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private SshOperationTimeoutException _actualException;
private Socket _clientSocket;
private AsyncSocketListener _proxyServer;
private Stopwatch _stopWatch;
private AsyncSocketListener _server;
private bool _disconnected;
protected override void SetupData()
{
base.SetupData();
var random = new Random();
_connectionInfo = CreateConnectionInfo("proxyUser", "proxyPwd");
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(random.Next(50, 200));
_stopWatch = new Stopwatch();
_actualException = null;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_proxyServer = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.ProxyPort));
_proxyServer.Disconnected += socket => _disconnected = true;
_proxyServer.Connected += socket =>
{
socket.Send(new byte[]
{
// Reply version (null byte)
0x00
});
};
_proxyServer.Start();
_server = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.Port));
_server.Start();
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_server != null)
{
_server.Dispose();
}
if (_proxyServer != null)
{
_proxyServer.Dispose();
}
}
protected override void Act()
{
_stopWatch.Start();
try
{
Connector.Connect(_connectionInfo);
Assert.Fail();
}
catch (SshOperationTimeoutException ex)
{
_actualException = ex;
}
finally
{
_stopWatch.Stop();
}
}
[TestMethod]
public void ConnectShouldHaveThrownSshOperationTimeoutException()
{
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual(string.Format(CultureInfo.InvariantCulture, "Socket read operation has timed out after {0:F0} milliseconds.", _connectionInfo.Timeout.TotalMilliseconds), _actualException.Message);
}
[TestMethod]
public void ConnectShouldHaveRespectedTimeout()
{
var errorText = string.Format("Elapsed: {0}, Timeout: {1}",
_stopWatch.ElapsedMilliseconds,
_connectionInfo.Timeout.TotalMilliseconds);
Assert.IsTrue(_stopWatch.ElapsedMilliseconds >= _connectionInfo.Timeout.TotalMilliseconds, errorText);
Assert.IsTrue(_stopWatch.ElapsedMilliseconds < (_connectionInfo.Timeout.TotalMilliseconds + 100), errorText);
}
[TestMethod]
public void ClientSocketShouldNotBeConnected()
{
Assert.IsTrue(_disconnected);
Assert.IsFalse(_clientSocket.Connected);
}
[TestMethod]
public void ClientSocketShouldHaveBeenDisposed()
{
try
{
_clientSocket.Receive(new byte[0]);
Assert.Fail();
}
catch (ObjectDisposedException)
{
}
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,131 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using Renci.SshNet.Connection;
using Renci.SshNet.Tests.Common;
using System;
using System.Diagnostics;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class Socks4ConnectorTest_Connect_TimeoutReadingReplyVersion : Socks4ConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private SshOperationTimeoutException _actualException;
private Socket _clientSocket;
private AsyncSocketListener _proxyServer;
private Stopwatch _stopWatch;
private AsyncSocketListener _server;
private bool _disconnected;
protected override void SetupData()
{
base.SetupData();
var random = new Random();
_connectionInfo = CreateConnectionInfo("proxyUser", "proxyPwd");
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(random.Next(50, 200));
_stopWatch = new Stopwatch();
_actualException = null;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_proxyServer = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.ProxyPort));
_proxyServer.Disconnected += socket => _disconnected = true;
_proxyServer.Start();
_server = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.Port));
_server.Start();
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_server != null)
{
_server.Dispose();
}
if (_proxyServer != null)
{
_proxyServer.Dispose();
}
}
protected override void Act()
{
_stopWatch.Start();
try
{
Connector.Connect(_connectionInfo);
Assert.Fail();
}
catch (SshOperationTimeoutException ex)
{
_actualException = ex;
}
finally
{
_stopWatch.Stop();
}
}
[TestMethod]
public void ConnectShouldHaveThrownSshOperationTimeoutException()
{
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual(string.Format(CultureInfo.InvariantCulture, "Socket read operation has timed out after {0:F0} milliseconds.", _connectionInfo.Timeout.TotalMilliseconds), _actualException.Message);
}
[TestMethod]
public void ConnectShouldHaveRespectedTimeout()
{
var errorText = string.Format("Elapsed: {0}, Timeout: {1}",
_stopWatch.ElapsedMilliseconds,
_connectionInfo.Timeout.TotalMilliseconds);
Assert.IsTrue(_stopWatch.ElapsedMilliseconds >= _connectionInfo.Timeout.TotalMilliseconds, errorText);
Assert.IsTrue(_stopWatch.ElapsedMilliseconds < (_connectionInfo.Timeout.TotalMilliseconds + 100), errorText);
}
[TestMethod]
public void ClientSocketShouldNotBeConnected()
{
Assert.IsTrue(_disconnected);
Assert.IsFalse(_clientSocket.Connected);
}
[TestMethod]
public void ClientSocketShouldHaveBeenDisposed()
{
try
{
_clientSocket.Receive(new byte[0]);
Assert.Fail();
}
catch (ObjectDisposedException)
{
}
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,68 @@
using Moq;
using Renci.SshNet.Connection;
using Renci.SshNet.Tests.Common;
using System;
using System.Net;
using System.Text;
namespace Renci.SshNet.Tests.Classes.Connection
{
public abstract class Socks5ConnectorTestBase : TripleATestBase
{
internal Mock<ISocketFactory> SocketFactoryMock { get; private set; }
internal Socks5Connector Connector { get; private set; }
internal SocketFactory SocketFactory { get; private set; }
protected virtual void CreateMocks()
{
SocketFactoryMock = new Mock<ISocketFactory>(MockBehavior.Strict);
}
protected virtual void SetupData()
{
Connector = new Socks5Connector(SocketFactoryMock.Object);
SocketFactory = new SocketFactory();
}
protected virtual void SetupMocks()
{
}
protected sealed override void Arrange()
{
CreateMocks();
SetupData();
SetupMocks();
}
protected ConnectionInfo CreateConnectionInfo(string proxyUser, string proxyPassword)
{
return new ConnectionInfo(IPAddress.Loopback.ToString(),
777,
"user",
ProxyTypes.Socks5,
IPAddress.Loopback.ToString(),
8122,
proxyUser,
proxyPassword,
new KeyboardInteractiveAuthenticationMethod("user"));
}
protected static string GenerateRandomString(int minLength, int maxLength)
{
var random = new Random();
var length = random.Next(minLength, maxLength);
var sb = new StringBuilder(length);
int offset = 'a';
for (var i = 0; i < length; i++)
{
var @char = (char) random.Next(offset, offset + 26);
sb.Append(@char);
}
return sb.ToString();
}
}
}
@@ -0,0 +1,103 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class Socks5ConnectorTest_Connect_ConnectionToProxyRefused : Socks5ConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private SocketException _actualException;
private Socket _clientSocket;
private Stopwatch _stopWatch;
protected override void SetupData()
{
base.SetupData();
_connectionInfo = CreateConnectionInfo("proxyUser", "proxyPwd");
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(5000);
_stopWatch = new Stopwatch();
_actualException = null;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_clientSocket != null)
{
_clientSocket.Dispose();
}
}
protected override void Act()
{
_stopWatch.Start();
try
{
Connector.Connect(_connectionInfo);
Assert.Fail();
}
catch (SocketException ex)
{
_actualException = ex;
}
finally
{
_stopWatch.Stop();
}
}
[TestMethod]
public void ConnectShouldHaveThrownSocketException()
{
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual(SocketError.ConnectionRefused, _actualException.SocketErrorCode);
}
[TestMethod]
public void ConnectShouldHaveRespectedTimeout()
{
var errorText = string.Format("Elapsed: {0}, Timeout: {1}",
_stopWatch.ElapsedMilliseconds,
_connectionInfo.Timeout.TotalMilliseconds);
Assert.IsTrue(_stopWatch.ElapsedMilliseconds < _connectionInfo.Timeout.TotalMilliseconds, errorText);
}
[TestMethod]
public void ClientSocketShouldHaveBeenDisposed()
{
try
{
_clientSocket.Receive(new byte[0]);
Assert.Fail();
}
catch (ObjectDisposedException)
{
}
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,206 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using Renci.SshNet.Tests.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class Socks5Connector_Connect_NoAuthentication_Succeed : Socks5ConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private AsyncSocketListener _proxyServer;
private Socket _clientSocket;
private List<byte> _bytesReceivedByProxy;
private Socket _actual;
protected override void SetupData()
{
base.SetupData();
_connectionInfo = CreateConnectionInfo(new string('a', 255), new string('b', 255));
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(100);
_bytesReceivedByProxy = new List<byte>();
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_proxyServer = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.ProxyPort));
_proxyServer.BytesReceived += (bytesReceived, socket) =>
{
_bytesReceivedByProxy.AddRange(bytesReceived);
if (_bytesReceivedByProxy.Count == 4)
{
// We received the greeting
socket.Send(new byte[]
{
// SOCKS version
0x05,
// Require no authentication
0x00
});
}
else if (_bytesReceivedByProxy.Count == 4 + (1 + 1 + 1 + 1 + 4 + 2))
{
// We received the connection request
socket.Send(new byte[]
{
// SOCKS version
0x05,
// Connection successful
0x00,
// Reserved byte
0x00,
});
// Send server bound address
socket.Send(new byte[]
{
// IPv6
0x04,
// IP address
0x01,
0x02,
0x12,
0x41,
0x31,
0x02,
0x42,
0x41,
0x71,
0x02,
0x32,
0x81,
0x01,
0x52,
0x12,
0x91,
// Port
0x0f,
0x1b,
});
// Send extra byte to allow us to verify that connector did not consume too much
socket.Send(new byte[]
{
0xff
});
}
};
_proxyServer.Start();
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_proxyServer != null)
{
_proxyServer.Dispose();
}
if (_clientSocket != null)
{
_clientSocket.Shutdown(SocketShutdown.Both);
_clientSocket.Dispose();
}
}
protected override void Act()
{
_actual = Connector.Connect(_connectionInfo);
}
[TestMethod]
public void ConnectShouldHaveReturnedSocketCreatedUsingSocketFactory()
{
Assert.IsNotNull(_actual);
Assert.AreSame(_clientSocket, _actual);
}
[TestMethod]
public void ClientSocketShouldBeConnected()
{
Assert.IsTrue(_clientSocket.Connected);
}
[TestMethod]
public void ProxyShouldHaveReceivedExpectedSocksRequest()
{
var expectedSocksRequest = new byte[]
{
//
// Client greeting
//
// SOCKS version
0x05,
// Number of authentication methods supported
0x02,
// No authentication
0x00,
// Username/password
0x02,
//
// Client connection request
//
// SOCKS version
0x05,
// Establish a TCP/IP stream connection
0x01,
// Reserved
0x00,
// Destination address type (IPv4)
0x01,
// Destination address (IPv4)
0x7f,
0x00,
0x00,
0x01,
// Destination port
0x03,
0x09
};
var errorText = string.Format("Expected:{0}{1}{0}but was:{0}{2}",
Environment.NewLine,
PacketDump.Create(expectedSocksRequest, 2),
PacketDump.Create(_bytesReceivedByProxy, 2));
Assert.IsTrue(expectedSocksRequest.SequenceEqual(_bytesReceivedByProxy), errorText);
}
[TestMethod]
public void OnlySocksResponseShouldHaveBeenConsumed()
{
var buffer = new byte[1];
var bytesRead = _clientSocket.Receive(buffer);
Assert.AreEqual(1, bytesRead);
Assert.AreEqual(0xff, buffer[0]);
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,123 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using Renci.SshNet.Tests.Common;
using System;
using System.Net;
using System.Net.Sockets;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class Socks5ConnectorTest_Connect_ProxySocksVersionIsNotSupported : Socks5ConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private AsyncSocketListener _proxyServer;
private Socket _clientSocket;
private byte _proxySocksVersion;
private bool _disconnected;
private ProxyException _actualException;
protected override void SetupData()
{
base.SetupData();
_connectionInfo = CreateConnectionInfo("proxyUser", "proxyPwd");
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(100);
_proxySocksVersion = GetNotSupportedSocksVersion();
_actualException = null;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_proxyServer = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.ProxyPort));
_proxyServer.Disconnected += socket => _disconnected = true;
_proxyServer.BytesReceived += (bytesReceived, socket) =>
{
socket.Send(new byte[] { _proxySocksVersion });
};
_proxyServer.Start();
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_proxyServer != null)
{
_proxyServer.Dispose();
}
if (_clientSocket != null)
{
_clientSocket.Dispose();
}
}
protected override void Act()
{
try
{
Connector.Connect(_connectionInfo);
Assert.Fail();
}
catch (ProxyException ex)
{
_actualException = ex;
}
}
[TestMethod]
public void ConnectShouldHaveThrownProxyException()
{
Assert.IsNotNull(_actualException);
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual(string.Format("SOCKS Version '{0}' is not supported.", _proxySocksVersion), _actualException.Message);
}
[TestMethod]
public void ConnectionToProxyShouldHaveBeenShutDown()
{
Assert.IsTrue(_disconnected);
}
[TestMethod]
public void ClientSocketShouldHaveBeenDisposed()
{
try
{
_clientSocket.Receive(new byte[0]);
Assert.Fail();
}
catch (ObjectDisposedException)
{
}
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
private static byte GetNotSupportedSocksVersion()
{
var random = new Random();
while (true)
{
var socksVersion = random.Next(1, 255);
if (socksVersion != 5)
{
return (byte) socksVersion;
}
}
}
}
}
@@ -0,0 +1,107 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using System;
using System.Diagnostics;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class Socks5ConnectorTest_Connect_TimeoutConnectingToProxy : Socks5ConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private SshOperationTimeoutException _actualException;
private Socket _clientSocket;
private Stopwatch _stopWatch;
protected override void SetupData()
{
base.SetupData();
var random = new Random();
_connectionInfo = CreateConnectionInfo("proxyUser", "proxyPwd");
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(random.Next(50, 200));
_stopWatch = new Stopwatch();
_actualException = null;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_clientSocket != null)
{
_clientSocket.Dispose();
}
}
protected override void Act()
{
_stopWatch.Start();
try
{
Connector.Connect(_connectionInfo);
Assert.Fail();
}
catch (SshOperationTimeoutException ex)
{
_actualException = ex;
}
finally
{
_stopWatch.Stop();
}
}
[TestMethod]
public void ConnectShouldHaveThrownSshOperationTimeoutException()
{
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual(string.Format(CultureInfo.InvariantCulture, "Connection failed to establish within {0} milliseconds.", _connectionInfo.Timeout.TotalMilliseconds), _actualException.Message);
}
[TestMethod]
public void ConnectShouldHaveRespectedTimeout()
{
var errorText = string.Format("Elapsed: {0}, Timeout: {1}",
_stopWatch.ElapsedMilliseconds,
_connectionInfo.Timeout.TotalMilliseconds);
Assert.IsTrue(_stopWatch.ElapsedMilliseconds >= _connectionInfo.Timeout.TotalMilliseconds, errorText);
Assert.IsTrue(_stopWatch.ElapsedMilliseconds < (_connectionInfo.Timeout.TotalMilliseconds + 100), errorText);
}
[TestMethod]
public void ClientSocketShouldHaveBeenDisposed()
{
try
{
_clientSocket.Receive(new byte[0]);
Assert.Fail();
}
catch (ObjectDisposedException)
{
}
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,177 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using Renci.SshNet.Tests.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_AuthenticationFailed : Socks5ConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private AsyncSocketListener _proxyServer;
private Socket _clientSocket;
private List<byte> _bytesReceivedByProxy;
private bool _disconnected;
private ProxyException _actualException;
protected override void SetupData()
{
base.SetupData();
_connectionInfo = CreateConnectionInfo("aa", "bbbb");
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(100);
_bytesReceivedByProxy = new List<byte>();
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_proxyServer = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.ProxyPort));
_proxyServer.Disconnected += socket => _disconnected = true;
_proxyServer.BytesReceived += (bytesReceived, socket) =>
{
_bytesReceivedByProxy.AddRange(bytesReceived);
if (_bytesReceivedByProxy.Count == 4)
{
// We received the greeting
socket.Send(new byte[]
{
// SOCKS version
0x05,
// Require username/password authentication
0x02
});
}
else if (_bytesReceivedByProxy.Count == 4 + (1 + 1 + 2 + 1 + 4))
{
// We received the username/password authentication request
socket.Send(new byte[]
{
// Authentication version
0x01,
// Authentication failed
0x01
});
}
};
_proxyServer.Start();
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_proxyServer != null)
{
_proxyServer.Dispose();
}
if (_clientSocket != null)
{
_clientSocket.Dispose();
}
}
protected override void Act()
{
try
{
Connector.Connect(_connectionInfo);
Assert.Fail();
}
catch (ProxyException ex)
{
_actualException = ex;
}
}
[TestMethod]
public void ConnectShouldHaveThrownProxyException()
{
Assert.IsNotNull(_actualException);
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual("SOCKS5: Username/Password authentication failed.", _actualException.Message);
}
[TestMethod]
public void ProxyShouldHaveReceivedExpectedSocksRequest()
{
var expectedSocksRequest = new List<byte>();
//
// Client greeting
//
// SOCKS version
expectedSocksRequest.Add(0x05);
// Number of authentication methods supported
expectedSocksRequest.Add(0x02);
// No authentication
expectedSocksRequest.Add(0x00);
// Username/password
expectedSocksRequest.Add(0x02);
//
// Username/password authentication request
//
// Version of the negotiation
expectedSocksRequest.Add(0x01);
// Length of the username
expectedSocksRequest.Add((byte) _connectionInfo.ProxyUsername.Length);
// Username
expectedSocksRequest.AddRange(Encoding.ASCII.GetBytes(_connectionInfo.ProxyUsername));
// Length of the password
expectedSocksRequest.Add((byte) _connectionInfo.ProxyPassword.Length);
// Password
expectedSocksRequest.AddRange(Encoding.ASCII.GetBytes(_connectionInfo.ProxyPassword));
var errorText = string.Format("Expected:{0}{1}{0}but was:{0}{2}",
Environment.NewLine,
PacketDump.Create(expectedSocksRequest, 2),
PacketDump.Create(_bytesReceivedByProxy, 2));
Assert.IsTrue(expectedSocksRequest.SequenceEqual(_bytesReceivedByProxy), errorText);
}
[TestMethod]
public void ConnectionToProxyShouldHaveBeenShutDown()
{
Assert.IsTrue(_disconnected);
}
[TestMethod]
public void ClientSocketShouldHaveBeenDisposed()
{
try
{
_clientSocket.Receive(new byte[0]);
Assert.Fail();
}
catch (ObjectDisposedException)
{
}
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,220 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using Renci.SshNet.Tests.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_ConnectionSucceeded : Socks5ConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private AsyncSocketListener _proxyServer;
private Socket _clientSocket;
private List<byte> _bytesReceivedByProxy;
private Socket _actual;
protected override void SetupData()
{
base.SetupData();
_connectionInfo = CreateConnectionInfo(GenerateRandomString(0, 255), GenerateRandomString(0, 255));
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(100);
_bytesReceivedByProxy = new List<byte>();
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_proxyServer = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.ProxyPort));
_proxyServer.BytesReceived += (bytesReceived, socket) =>
{
_bytesReceivedByProxy.AddRange(bytesReceived);
if (_bytesReceivedByProxy.Count == 4)
{
// We received the greeting
socket.Send(new byte[]
{
// SOCKS version
0x05,
// Require username/password authentication
0x02
});
}
else if (_bytesReceivedByProxy.Count == 4 + (1 + 1 + _connectionInfo.ProxyUsername.Length + 1 + _connectionInfo.ProxyPassword.Length))
{
// We received the username/password authentication request
socket.Send(new byte[]
{
// Authentication version
0x01,
// Authentication successful
0x00
});
}
else if (_bytesReceivedByProxy.Count == 4 + (1 + 1 + _connectionInfo.ProxyUsername.Length + 1 + _connectionInfo.ProxyPassword.Length) + (1 + 1 + 1 + 1 + 4 + 2))
{
// We received the connection request
socket.Send(new byte[]
{
// SOCKS version
0x05,
// Connection successful
0x00,
// Reserved byte
0x00,
});
// Send server bound address
socket.Send(new byte[]
{
// IPv4
0x01,
// IP address
0x01,
0x02,
0x12,
0x41,
// Port
0x01,
0x02,
});
// Send extra byte to allow us to verify that connector did not consume too much
socket.Send(new byte[]
{
0xfe
});
}
};
_proxyServer.Start();
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_proxyServer != null)
{
_proxyServer.Dispose();
}
if (_clientSocket != null)
{
_clientSocket.Shutdown(SocketShutdown.Both);
_clientSocket.Dispose();
}
}
protected override void Act()
{
_actual = Connector.Connect(_connectionInfo);
}
[TestMethod]
public void ConnectShouldHaveReturnedSocketCreatedUsingSocketFactory()
{
Assert.IsNotNull(_actual);
Assert.AreSame(_clientSocket, _actual);
}
[TestMethod]
public void ClientSocketShouldBeConnected()
{
Assert.IsTrue(_clientSocket.Connected);
}
[TestMethod]
public void ProxyShouldHaveReceivedExpectedSocksRequest()
{
var expectedSocksRequest = new List<byte>();
//
// Client greeting
//
// SOCKS version
expectedSocksRequest.Add(0x05);
// Number of authentication methods supported
expectedSocksRequest.Add(0x02);
// No authentication
expectedSocksRequest.Add(0x00);
// Username/password
expectedSocksRequest.Add(0x02);
//
// Username/password authentication request
//
// Version of the negotiation
expectedSocksRequest.Add(0x01);
// Length of the username
expectedSocksRequest.Add((byte)_connectionInfo.ProxyUsername.Length);
// Username
expectedSocksRequest.AddRange(Encoding.ASCII.GetBytes(_connectionInfo.ProxyUsername));
// Length of the password
expectedSocksRequest.Add((byte)_connectionInfo.ProxyPassword.Length);
// Password
expectedSocksRequest.AddRange(Encoding.ASCII.GetBytes(_connectionInfo.ProxyPassword));
//
// Client connection request
//
// SOCKS version
expectedSocksRequest.Add(0x05);
// Establish a TCP/IP stream connection
expectedSocksRequest.Add(0x01);
// Reserved
expectedSocksRequest.Add(0x00);
// Destination address type (IPv4)
expectedSocksRequest.Add(0x01);
// Destination address (IPv4)
expectedSocksRequest.Add(0x7f);
expectedSocksRequest.Add(0x00);
expectedSocksRequest.Add(0x00);
expectedSocksRequest.Add(0x01);
// Destination port
expectedSocksRequest.Add(0x03);
expectedSocksRequest.Add(0x09);
var errorText = string.Format("Expected:{0}{1}{0}but was:{0}{2}",
Environment.NewLine,
PacketDump.Create(expectedSocksRequest, 2),
PacketDump.Create(_bytesReceivedByProxy, 2));
Assert.IsTrue(expectedSocksRequest.SequenceEqual(_bytesReceivedByProxy), errorText);
}
[TestMethod]
public void OnlySocksResponseShouldHaveBeenConsumed()
{
var buffer = new byte[1];
var bytesRead = _clientSocket.Receive(buffer);
Assert.AreEqual(1, bytesRead);
Assert.AreEqual(0xfe, buffer[0]);
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,149 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using Renci.SshNet.Tests.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_PasswordExceedsMaximumLength : Socks5ConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private AsyncSocketListener _proxyServer;
private Socket _clientSocket;
private List<byte> _bytesReceivedByProxy;
private bool _disconnected;
private ProxyException _actualException;
protected override void SetupData()
{
base.SetupData();
_connectionInfo = CreateConnectionInfo(new string('a', 255), new string('b', 256));
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(100);
_bytesReceivedByProxy = new List<byte>();
_actualException = null;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_proxyServer = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.ProxyPort));
_proxyServer.Disconnected += socket => _disconnected = true;
_proxyServer.BytesReceived += (bytesReceived, socket) =>
{
_bytesReceivedByProxy.AddRange(bytesReceived);
// Wait until we received the greeting
if (_bytesReceivedByProxy.Count == 4)
{
socket.Send(new byte[]
{
// SOCKS version
0x05,
// Username/password authentication
0x02
});
}
};
_proxyServer.Start();
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_proxyServer != null)
{
_proxyServer.Dispose();
}
if (_clientSocket != null)
{
_clientSocket.Dispose();
}
}
protected override void Act()
{
try
{
Connector.Connect(_connectionInfo);
Assert.Fail();
}
catch (ProxyException ex)
{
_actualException = ex;
}
}
[TestMethod]
public void ConnectShouldHaveThrownProxyException()
{
Assert.IsNotNull(_actualException);
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual("Proxy password is too long.", _actualException.Message);
}
[TestMethod]
public void ProxyShouldHaveReceivedExpectedSocksRequest()
{
var expectedSocksRequest = new List<byte>();
//
// Client greeting
//
// SOCKS version
expectedSocksRequest.Add(0x05);
// Number of authentication methods supported
expectedSocksRequest.Add(0x02);
// No authentication
expectedSocksRequest.Add(0x00);
// Username/password
expectedSocksRequest.Add(0x02);
var errorText = string.Format("Expected:{0}{1}{0}but was:{0}{2}",
Environment.NewLine,
PacketDump.Create(expectedSocksRequest, 2),
PacketDump.Create(_bytesReceivedByProxy, 2));
Assert.IsTrue(expectedSocksRequest.SequenceEqual(_bytesReceivedByProxy), errorText);
}
[TestMethod]
public void ConnectionToProxyShouldHaveBeenShutDown()
{
Assert.IsTrue(_disconnected);
}
[TestMethod]
public void ClientSocketShouldHaveBeenDisposed()
{
try
{
_clientSocket.Receive(new byte[0]);
Assert.Fail();
}
catch (ObjectDisposedException)
{
}
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,149 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using Renci.SshNet.Tests.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
namespace Renci.SshNet.Tests.Classes.Connection
{
[TestClass]
public class Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_UserNameExceedsMaximumLength : Socks5ConnectorTestBase
{
private ConnectionInfo _connectionInfo;
private AsyncSocketListener _proxyServer;
private Socket _clientSocket;
private List<byte> _bytesReceivedByProxy;
private bool _disconnected;
private ProxyException _actualException;
protected override void SetupData()
{
base.SetupData();
_connectionInfo = CreateConnectionInfo(new string('a', 256), new string('b', 255));
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(100);
_bytesReceivedByProxy = new List<byte>();
_actualException = null;
_clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_proxyServer = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.ProxyPort));
_proxyServer.Disconnected += socket => _disconnected = true;
_proxyServer.BytesReceived += (bytesReceived, socket) =>
{
_bytesReceivedByProxy.AddRange(bytesReceived);
// Wait until we received the greeting
if (_bytesReceivedByProxy.Count == 4)
{
socket.Send(new byte[]
{
// SOCKS version
0x05,
// Username/password authentication
0x02
});
}
};
_proxyServer.Start();
}
protected override void SetupMocks()
{
SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
.Returns(_clientSocket);
}
protected override void TearDown()
{
base.TearDown();
if (_proxyServer != null)
{
_proxyServer.Dispose();
}
if (_clientSocket != null)
{
_clientSocket.Dispose();
}
}
protected override void Act()
{
try
{
Connector.Connect(_connectionInfo);
Assert.Fail();
}
catch (ProxyException ex)
{
_actualException = ex;
}
}
[TestMethod]
public void ConnectShouldHaveThrownProxyException()
{
Assert.IsNotNull(_actualException);
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual("Proxy username is too long.", _actualException.Message);
}
[TestMethod]
public void ProxyShouldHaveReceivedExpectedSocksRequest()
{
var expectedSocksRequest = new List<byte>();
//
// Client greeting
//
// SOCKS version
expectedSocksRequest.Add(0x05);
// Number of authentication methods supported
expectedSocksRequest.Add(0x02);
// No authentication
expectedSocksRequest.Add(0x00);
// Username/password
expectedSocksRequest.Add(0x02);
var errorText = string.Format("Expected:{0}{1}{0}but was:{0}{2}",
Environment.NewLine,
PacketDump.Create(expectedSocksRequest, 2),
PacketDump.Create(_bytesReceivedByProxy, 2));
Assert.IsTrue(expectedSocksRequest.SequenceEqual(_bytesReceivedByProxy), errorText);
}
[TestMethod]
public void ConnectionToProxyShouldHaveBeenShutDown()
{
Assert.IsTrue(_disconnected);
}
[TestMethod]
public void ClientSocketShouldHaveBeenDisposed()
{
try
{
_clientSocket.Receive(new byte[0]);
Assert.Fail();
}
catch (ObjectDisposedException)
{
}
}
[TestMethod]
public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce()
{
SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp),
Times.Once());
}
}
}
@@ -0,0 +1,17 @@
using Moq;
using Renci.SshNet.NetConf;
namespace Renci.SshNet.Tests.Classes
{
public abstract class NetConfClientTestBase : BaseClientTestBase
{
internal Mock<INetConfSession> _netConfSessionMock { get; private set; }
protected override void CreateMocks()
{
base.CreateMocks();
_netConfSessionMock = new Mock<INetConfSession>(MockBehavior.Strict);
}
}
}
@@ -10,51 +10,29 @@ using Renci.SshNet.Security;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class NetConfClientTest_Connect_NetConfSessionConnectFailure
public class NetConfClientTest_Connect_NetConfSessionConnectFailure : NetConfClientTestBase
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private Mock<INetConfSession> _netConfSessionMock;
private ConnectionInfo _connectionInfo;
private ApplicationException _netConfSessionConnectionException;
private NetConfClient _netConfClient;
private ApplicationException _actualException;
[TestInitialize]
public void Setup()
{
Arrange();
Act();
}
private void Arrange()
{
SetupData();
CreateMocks();
SetupMocks();
_netConfClient = new NetConfClient(_connectionInfo, false, _serviceFactoryMock.Object);
}
private void SetupData()
protected override void SetupData()
{
_connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth"));
_netConfSessionConnectionException = new ApplicationException();
_netConfClient = new NetConfClient(_connectionInfo, false, _serviceFactoryMock.Object);
}
private void CreateMocks()
{
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
_netConfSessionMock = new Mock<INetConfSession>(MockBehavior.Strict);
}
private void SetupMocks()
protected override void SetupMocks()
{
var sequence = new MockSequence();
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo))
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence)
.Setup(p => p.Connect());
@@ -70,7 +48,7 @@ namespace Renci.SshNet.Tests.Classes
.Setup(p => p.Dispose());
}
private void Act()
protected override void Act()
{
try
{
@@ -6,56 +6,55 @@ using System;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class NetConfClientTest_Dispose_Connected
public class NetConfClientTest_Dispose_Connected : NetConfClientTestBase
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private Mock<INetConfSession> _netConfSessionMock;
private NetConfClient _netConfClient;
private ConnectionInfo _connectionInfo;
private int _operationTimeout;
[TestInitialize]
public void Setup()
protected override void SetupData()
{
Arrange();
Act();
}
[TestCleanup]
public void Cleanup()
{
}
protected void Arrange()
{
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
_netConfSessionMock = new Mock<INetConfSession>(MockBehavior.Strict);
_connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth"));
_operationTimeout = new Random().Next(1000, 10000);
_netConfClient = new NetConfClient(_connectionInfo, false, _serviceFactoryMock.Object);
_netConfClient.OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout);
}
protected override void SetupMocks()
{
var sequence = new MockSequence();
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence).Setup(p => p.Connect());
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateNetConfSession(_sessionMock.Object, _operationTimeout))
.Returns(_netConfSessionMock.Object);
_netConfSessionMock.InSequence(sequence).Setup(p => p.Connect());
_sessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting());
_netConfSessionMock.InSequence(sequence).Setup(p => p.Disconnect());
_sessionMock.InSequence(sequence).Setup(p => p.Dispose());
_netConfSessionMock.InSequence(sequence).Setup(p => p.Dispose());
.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence)
.Setup(p => p.Connect());
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateNetConfSession(_sessionMock.Object, _operationTimeout))
.Returns(_netConfSessionMock.Object);
_netConfSessionMock.InSequence(sequence)
.Setup(p => p.Connect());
_sessionMock.InSequence(sequence)
.Setup(p => p.OnDisconnecting());
_netConfSessionMock.InSequence(sequence)
.Setup(p => p.Disconnect());
_sessionMock.InSequence(sequence)
.Setup(p => p.Dispose());
_netConfSessionMock.InSequence(sequence)
.Setup(p => p.Dispose());
}
protected override void Arrange()
{
base.Arrange();
_netConfClient.Connect();
}
protected void Act()
protected override void Act()
{
_netConfClient.Dispose();
}
@@ -66,10 +65,17 @@ namespace Renci.SshNet.Tests.Classes
_serviceFactoryMock.Verify(p => p.CreateNetConfSession(_sessionMock.Object, _operationTimeout), Times.Once);
}
[TestMethod]
public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once);
}
[TestMethod]
public void CreateSessionOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo), Times.Once);
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object),
Times.Once);
}
[TestMethod]
@@ -6,11 +6,8 @@ using System;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class NetConfClientTest_Dispose_Disconnected
public class NetConfClientTest_Dispose_Disconnected : NetConfClientTestBase
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private Mock<INetConfSession> _netConfSessionMock;
private NetConfClient _netConfClient;
private ConnectionInfo _connectionInfo;
private int _operationTimeout;
@@ -27,37 +24,45 @@ namespace Renci.SshNet.Tests.Classes
{
}
protected void Arrange()
protected override void SetupData()
{
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
_netConfSessionMock = new Mock<INetConfSession>(MockBehavior.Strict);
_connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth"));
_operationTimeout = new Random().Next(1000, 10000);
_netConfClient = new NetConfClient(_connectionInfo, false, _serviceFactoryMock.Object);
_netConfClient.OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout);
}
protected override void SetupMocks()
{
var sequence = new MockSequence();
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo))
.Returns(_sessionMock.Object);
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence).Setup(p => p.Connect());
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateNetConfSession(_sessionMock.Object, _operationTimeout))
.Returns(_netConfSessionMock.Object);
.Setup(p => p.CreateNetConfSession(_sessionMock.Object, _operationTimeout))
.Returns(_netConfSessionMock.Object);
_netConfSessionMock.InSequence(sequence).Setup(p => p.Connect());
_sessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting());
_netConfSessionMock.InSequence(sequence).Setup(p => p.Disconnect());
_sessionMock.InSequence(sequence).Setup(p => p.Dispose());
_netConfSessionMock.InSequence(sequence).Setup(p => p.Disconnect());
_netConfSessionMock.InSequence(sequence).Setup(p => p.Dispose());
}
protected override void Arrange()
{
base.Arrange();
_netConfClient.Connect();
_netConfClient.Disconnect();
}
protected void Act()
protected override void Act()
{
_netConfClient.Dispose();
}
@@ -68,10 +73,17 @@ namespace Renci.SshNet.Tests.Classes
_serviceFactoryMock.Verify(p => p.CreateNetConfSession(_sessionMock.Object, _operationTimeout), Times.Once);
}
[TestMethod]
public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once);
}
[TestMethod]
public void CreateSessionOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo), Times.Once);
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object),
Times.Once);
}
[TestMethod]
@@ -6,57 +6,50 @@ using System;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class NetConfClientTest_Dispose_Disposed
public class NetConfClientTest_Dispose_Disposed : NetConfClientTestBase
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private Mock<INetConfSession> _netConfSessionMock;
private NetConfClient _netConfClient;
private ConnectionInfo _connectionInfo;
private int _operationTimeout;
[TestInitialize]
public void Setup()
protected override void SetupData()
{
Arrange();
Act();
}
[TestCleanup]
public void Cleanup()
{
}
protected void Arrange()
{
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
_netConfSessionMock = new Mock<INetConfSession>(MockBehavior.Strict);
_connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth"));
_operationTimeout = new Random().Next(1000, 10000);
_netConfClient = new NetConfClient(_connectionInfo, false, _serviceFactoryMock.Object);
_netConfClient.OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout);
}
protected override void SetupMocks()
{
var sequence = new MockSequence();
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo))
.Returns(_sessionMock.Object);
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence).Setup(p => p.Connect());
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateNetConfSession(_sessionMock.Object, _operationTimeout))
.Returns(_netConfSessionMock.Object);
.Setup(p => p.CreateNetConfSession(_sessionMock.Object, _operationTimeout))
.Returns(_netConfSessionMock.Object);
_netConfSessionMock.InSequence(sequence).Setup(p => p.Connect());
_sessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting());
_netConfSessionMock.InSequence(sequence).Setup(p => p.Disconnect());
_sessionMock.InSequence(sequence).Setup(p => p.Dispose());
_netConfSessionMock.InSequence(sequence).Setup(p => p.Dispose());
}
protected override void Arrange()
{
base.Arrange();
_netConfClient.Connect();
_netConfClient.Dispose();
}
protected void Act()
protected override void Act()
{
_netConfClient.Dispose();
}
@@ -67,10 +60,17 @@ namespace Renci.SshNet.Tests.Classes
_serviceFactoryMock.Verify(p => p.CreateNetConfSession(_sessionMock.Object, _operationTimeout), Times.Once);
}
[TestMethod]
public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once);
}
[TestMethod]
public void CreateSessionOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo), Times.Once);
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object),
Times.Once);
}
[TestMethod]
@@ -1,59 +1,58 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.NetConf;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class NetConfClientTest_Finalize_Connected
public class NetConfClientTest_Finalize_Connected : NetConfClientTestBase
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private Mock<INetConfSession> _netConfSessionMock;
private NetConfClient _netConfClient;
private ConnectionInfo _connectionInfo;
private int _operationTimeout;
private WeakReference _netConfClientWeakRefence;
[TestInitialize]
public void Setup()
protected override void SetupData()
{
Arrange();
Act();
}
protected void Arrange()
{
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Loose);
_sessionMock = new Mock<ISession>(MockBehavior.Loose);
_netConfSessionMock = new Mock<INetConfSession>(MockBehavior.Loose);
_connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth"));
_operationTimeout = new Random().Next(1000, 10000);
_netConfClient = new NetConfClient(_connectionInfo, false, _serviceFactoryMock.Object);
_netConfClient.OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout);
_netConfClientWeakRefence = new WeakReference(_netConfClient);
}
protected override void SetupMocks()
{
var sequence = new MockSequence();
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence).Setup(p => p.Connect());
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateNetConfSession(_sessionMock.Object, _operationTimeout))
.Returns(_netConfSessionMock.Object);
_netConfSessionMock.InSequence(sequence).Setup(p => p.Connect());
.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence)
.Setup(p => p.Connect());
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateNetConfSession(_sessionMock.Object, _operationTimeout))
.Returns(_netConfSessionMock.Object);
_netConfSessionMock.InSequence(sequence)
.Setup(p => p.Connect());
}
protected override void Arrange()
{
base.Arrange();
_netConfClient.Connect();
_netConfClient = null;
// we need to dereference all other mocks as they might otherwise hold the target alive
_sessionMock = null;
_connectionInfo = null;
_serviceFactoryMock = null;
// We need to dereference all mocks as they might otherwise hold the target alive
//(through recorded invocations?)
CreateMocks();
}
protected void Act()
protected override void Act()
{
GC.Collect();
GC.WaitForPendingFinalizers();
@@ -62,13 +61,25 @@ namespace Renci.SshNet.Tests.Classes
[TestMethod]
public void DisconnectOnNetConfSessionShouldBeInvokedOnce()
{
// Since we recreated the mocks, this test has no value
// We'll leaving ths test just in case we have a solution that does not require us
// to recreate the mocks
_netConfSessionMock.Verify(p => p.Disconnect(), Times.Never);
}
[TestMethod]
public void DisposeOnNetConfSessionShouldBeInvokedOnce()
{
// Since we recreated the mocks, this test has no value
// We'll leaving ths test just in case we have a solution that does not require us
// to recreate the mocks
_netConfSessionMock.Verify(p => p.Dispose(), Times.Never);
}
[TestMethod]
public void NetConfClientShouldHaveBeenFinalized()
{
Assert.IsNull(_netConfClientWeakRefence.Target);
}
}
}
@@ -1,45 +1,22 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Moq;
using Renci.SshNet.Channels;
using Renci.SshNet.Common;
namespace Renci.SshNet.Tests.Classes
{
public abstract class ScpClientTestBase
public abstract class ScpClientTestBase : BaseClientTestBase
{
internal Mock<IServiceFactory> _serviceFactoryMock;
internal Mock<IRemotePathTransformation> _remotePathTransformationMock;
internal Mock<ISession> _sessionMock;
internal Mock<IChannelSession> _channelSessionMock;
internal Mock<PipeStream> _pipeStreamMock;
protected abstract void SetupData();
protected void CreateMocks()
protected override void CreateMocks()
{
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
base.CreateMocks();
_remotePathTransformationMock = new Mock<IRemotePathTransformation>(MockBehavior.Strict);
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
_channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
_pipeStreamMock = new Mock<PipeStream>(MockBehavior.Strict);
}
protected abstract void SetupMocks();
protected virtual void Arrange()
{
SetupData();
CreateMocks();
SetupMocks();
}
[TestInitialize]
public void Initialize()
{
Arrange();
Act();
}
protected abstract void Act();
}
}
@@ -38,7 +38,10 @@ namespace Renci.SshNet.Tests.Classes
.Setup(p => p.CreateRemotePathDoubleQuoteTransformation())
.Returns(_remotePathTransformationMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo))
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence).Setup(p => p.Connect());
_serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object);
@@ -38,7 +38,10 @@ namespace Renci.SshNet.Tests.Classes
.Setup(p => p.CreateRemotePathDoubleQuoteTransformation())
.Returns(_remotePathTransformationMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo))
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence).Setup(p => p.Connect());
_serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object);
@@ -47,7 +47,10 @@ namespace Renci.SshNet.Tests.Classes
.Setup(p => p.CreateRemotePathDoubleQuoteTransformation())
.Returns(_remotePathTransformationMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo))
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence).Setup(p => p.Connect());
_serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object);
@@ -37,7 +37,10 @@ namespace Renci.SshNet.Tests.Classes
.Setup(p => p.CreateRemotePathDoubleQuoteTransformation())
.Returns(_remotePathTransformationMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo))
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence).Setup(p => p.Connect());
_serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object);
@@ -53,7 +53,10 @@ namespace Renci.SshNet.Tests.Classes
.Setup(p => p.CreateRemotePathDoubleQuoteTransformation())
.Returns(_remotePathTransformationMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo))
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence).Setup(p => p.Connect());
_serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object);
@@ -60,7 +60,10 @@ namespace Renci.SshNet.Tests.Classes
.Setup(p => p.CreateRemotePathDoubleQuoteTransformation())
.Returns(_remotePathTransformationMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo))
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence).Setup(p => p.Connect());
_serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object);
@@ -50,7 +50,10 @@ namespace Renci.SshNet.Tests.Classes
.Setup(p => p.CreateRemotePathDoubleQuoteTransformation())
.Returns(_remotePathTransformationMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo))
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence).Setup(p => p.Connect());
_serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object);
@@ -10,6 +10,7 @@ namespace Renci.SshNet.Tests.Classes
{
private ServiceFactory _serviceFactory;
private Mock<IConnectionInfo> _connectionInfoMock;
private Mock<ISocketFactory> _socketFactoryMock;
[TestInitialize]
public void Setup()
@@ -25,7 +26,7 @@ namespace Renci.SshNet.Tests.Classes
try
{
_serviceFactory.CreateConnector(connectionInfo);
_serviceFactory.CreateConnector(connectionInfo, _socketFactoryMock.Object);
Assert.Fail();
}
catch (ArgumentNullException ex)
@@ -35,16 +36,36 @@ namespace Renci.SshNet.Tests.Classes
}
}
[TestMethod]
public void SocketFactoryIsNull()
{
const ISocketFactory socketFactory = null;
try
{
_serviceFactory.CreateConnector(_connectionInfoMock.Object, socketFactory);
Assert.Fail();
}
catch (ArgumentNullException ex)
{
Assert.IsNull(ex.InnerException);
Assert.AreEqual("socketFactory", ex.ParamName);
}
}
[TestMethod]
public void ProxyType_Http()
{
_connectionInfoMock.Setup(p => p.ProxyType).Returns(ProxyTypes.Http);
var actual = _serviceFactory.CreateConnector(_connectionInfoMock.Object);
var actual = _serviceFactory.CreateConnector(_connectionInfoMock.Object, _socketFactoryMock.Object);
Assert.IsNotNull(actual);
Assert.AreEqual(typeof(HttpConnector), actual.GetType());
var httpConnector = (HttpConnector) actual;
Assert.AreSame(_socketFactoryMock.Object, httpConnector.SocketFactory);
_connectionInfoMock.Verify(p => p.ProxyType, Times.Once);
}
@@ -53,11 +74,14 @@ namespace Renci.SshNet.Tests.Classes
{
_connectionInfoMock.Setup(p => p.ProxyType).Returns(ProxyTypes.None);
var actual = _serviceFactory.CreateConnector(_connectionInfoMock.Object);
var actual = _serviceFactory.CreateConnector(_connectionInfoMock.Object, _socketFactoryMock.Object);
Assert.IsNotNull(actual);
Assert.AreEqual(typeof(DirectConnector), actual.GetType());
var directConnector = (DirectConnector) actual;
Assert.AreSame(_socketFactoryMock.Object, directConnector.SocketFactory);
_connectionInfoMock.Verify(p => p.ProxyType, Times.Once);
}
@@ -66,11 +90,14 @@ namespace Renci.SshNet.Tests.Classes
{
_connectionInfoMock.Setup(p => p.ProxyType).Returns(ProxyTypes.Socks4);
var actual = _serviceFactory.CreateConnector(_connectionInfoMock.Object);
var actual = _serviceFactory.CreateConnector(_connectionInfoMock.Object, _socketFactoryMock.Object);
Assert.IsNotNull(actual);
Assert.AreEqual(typeof(Socks4Connector), actual.GetType());
var socks4Connector = (Socks4Connector) actual;
Assert.AreSame(_socketFactoryMock.Object, socks4Connector.SocketFactory);
_connectionInfoMock.Verify(p => p.ProxyType, Times.Once);
}
@@ -79,11 +106,33 @@ namespace Renci.SshNet.Tests.Classes
{
_connectionInfoMock.Setup(p => p.ProxyType).Returns(ProxyTypes.Socks5);
var actual = _serviceFactory.CreateConnector(_connectionInfoMock.Object);
var actual = _serviceFactory.CreateConnector(_connectionInfoMock.Object, _socketFactoryMock.Object);
Assert.IsNotNull(actual);
Assert.AreEqual(typeof(Socks5Connector), actual.GetType());
var socks5Connector = (Socks5Connector) actual;
Assert.AreSame(_socketFactoryMock.Object, socks5Connector.SocketFactory);
_connectionInfoMock.Verify(p => p.ProxyType, Times.Once);
}
[TestMethod]
public void ProxyType_Undefined()
{
_connectionInfoMock.Setup(p => p.ProxyType).Returns((ProxyTypes) 666);
try
{
_serviceFactory.CreateConnector(_connectionInfoMock.Object, _socketFactoryMock.Object);
Assert.Fail();
}
catch (NotSupportedException ex)
{
Assert.IsNull(ex.InnerException);
Assert.AreEqual("ProxyTypes '666' is not supported.", ex.Message);
}
_connectionInfoMock.Verify(p => p.ProxyType, Times.Once);
}
}
@@ -11,286 +11,6 @@ namespace Renci.SshNet.Tests.Classes
{
public partial class SessionTest
{
[TestMethod]
public void ConnectShouldThrowProxyExceptionWhenHttpProxyResponseDoesNotContainStatusLine()
{
var proxyEndPoint = new IPEndPoint(IPAddress.Loopback, 8123);
var serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
using (var proxyStub = new HttpProxyStub(proxyEndPoint))
{
proxyStub.Responses.Add(Encoding.ASCII.GetBytes("Whatever\r\n"));
proxyStub.Start();
var connectionInfo = CreateConnectionInfoWithHttpProxy(proxyEndPoint, serverEndPoint, "anon");
using (var session = new Session(connectionInfo, _serviceFactoryMock.Object))
{
_serviceFactoryMock.Setup(p => p.CreateConnector(connectionInfo))
.Returns(_connectorMock.Object);
_connectorMock.Setup(p => p.Connect(connectionInfo))
.Returns<IConnectionInfo>(c => new HttpConnector().Connect(c));
try
{
session.Connect();
Assert.Fail();
}
catch (ProxyException ex)
{
Assert.IsNull(ex.InnerException);
Assert.AreEqual("HTTP response does not contain status line.", ex.Message);
}
}
}
}
[TestMethod]
public void ConnectShouldThrowProxyExceptionWhenHttpProxyReturnsHttpStatusOtherThan200()
{
var proxyEndPoint = new IPEndPoint(IPAddress.Loopback, 8123);
var serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
using (var proxyStub = new HttpProxyStub(proxyEndPoint))
{
proxyStub.Responses.Add(Encoding.ASCII.GetBytes("HTTP/1.0 501 Custom\r\n"));
proxyStub.Start();
var connectionInfo = CreateConnectionInfoWithHttpProxy(proxyEndPoint, serverEndPoint, "anon");
using (var session = new Session(connectionInfo, _serviceFactoryMock.Object))
{
_serviceFactoryMock.Setup(p => p.CreateConnector(connectionInfo))
.Returns(_connectorMock.Object);
_connectorMock.Setup(p => p.Connect(connectionInfo))
.Returns<IConnectionInfo>(c => new HttpConnector().Connect(c));
try
{
session.Connect();
Assert.Fail();
}
catch (ProxyException ex)
{
Assert.IsNull(ex.InnerException);
Assert.AreEqual("HTTP: Status code 501, \"Custom\"", ex.Message);
}
}
}
}
[TestMethod]
public void ConnectShouldSkipHeadersWhenHttpProxyReturnsHttpStatus200()
{
var proxyEndPoint = new IPEndPoint(IPAddress.Loopback, 8123);
var serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
using (var proxyStub = new HttpProxyStub(proxyEndPoint))
{
proxyStub.Responses.Add(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n"));
proxyStub.Responses.Add(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n"));
proxyStub.Responses.Add(Encoding.ASCII.GetBytes("\r\n"));
proxyStub.Responses.Add(Encoding.ASCII.GetBytes("SSH-666-SshStub"));
proxyStub.Start();
var connectionInfo = CreateConnectionInfoWithHttpProxy(proxyEndPoint, serverEndPoint, "anon");
using (var session = new Session(connectionInfo, _serviceFactoryMock.Object))
{
_serviceFactoryMock.Setup(p => p.CreateConnector(connectionInfo))
.Returns(_connectorMock.Object);
_connectorMock.Setup(p => p.Connect(connectionInfo))
.Returns<IConnectionInfo>(c => new HttpConnector().Connect(c));
try
{
session.Connect();
Assert.Fail();
}
catch (SshConnectionException ex)
{
Assert.IsNull(ex.InnerException);
Assert.AreEqual("Server version '666' is not supported.", ex.Message);
}
}
}
}
[TestMethod]
public void ConnectShouldSkipContentWhenHttpProxyReturnsHttpStatus200()
{
var proxyEndPoint = new IPEndPoint(IPAddress.Loopback, 8123);
var serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
using (var proxyStub = new HttpProxyStub(proxyEndPoint))
{
proxyStub.Responses.Add(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n"));
proxyStub.Responses.Add(Encoding.ASCII.GetBytes("Content-Length: 13\r\n"));
proxyStub.Responses.Add(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n"));
proxyStub.Responses.Add(Encoding.ASCII.GetBytes("\r\n"));
proxyStub.Responses.Add(Encoding.ASCII.GetBytes("DUMMY_CONTENT"));
proxyStub.Responses.Add(Encoding.ASCII.GetBytes("SSH-666-SshStub"));
proxyStub.Start();
var connectionInfo = CreateConnectionInfoWithHttpProxy(proxyEndPoint, serverEndPoint, "anon");
using (var session = new Session(connectionInfo, _serviceFactoryMock.Object))
{
_serviceFactoryMock.Setup(p => p.CreateConnector(connectionInfo))
.Returns(_connectorMock.Object);
_connectorMock.Setup(p => p.Connect(connectionInfo))
.Returns<IConnectionInfo>(c => new HttpConnector().Connect(c));
try
{
session.Connect();
Assert.Fail();
}
catch (SshConnectionException ex)
{
Assert.IsNull(ex.InnerException);
Assert.AreEqual("Server version '666' is not supported.", ex.Message);
}
}
}
}
[TestMethod]
public void ConnectShouldWriteConnectMethodToHttpProxy()
{
var proxyEndPoint = new IPEndPoint(IPAddress.Loopback, 8123);
var serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
using (var proxyStub = new HttpProxyStub(proxyEndPoint))
{
proxyStub.Responses.Add(Encoding.ASCII.GetBytes("HTTP/1.0 501 Custom\r\n"));
proxyStub.Start();
var connectionInfo = CreateConnectionInfoWithHttpProxy(proxyEndPoint, serverEndPoint, "anon");
using (var session = new Session(connectionInfo, _serviceFactoryMock.Object))
{
_serviceFactoryMock.Setup(p => p.CreateConnector(connectionInfo))
.Returns(_connectorMock.Object);
_connectorMock.Setup(p => p.Connect(connectionInfo))
.Returns<IConnectionInfo>(c => new HttpConnector().Connect(c));
try
{
session.Connect();
Assert.Fail();
}
catch (ProxyException)
{
}
}
Assert.AreEqual(string.Format("CONNECT {0} HTTP/1.0", serverEndPoint), proxyStub.HttpRequest.RequestLine);
}
}
[TestMethod]
public void ConnectShouldWriteProxyAuthorizationToHttpProxyWhenProxyUserNameIsNotNullAndNotEmpty()
{
var proxyEndPoint = new IPEndPoint(IPAddress.Loopback, 8123);
var serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
using (var proxyStub = new HttpProxyStub(proxyEndPoint))
{
proxyStub.Responses.Add(Encoding.ASCII.GetBytes("HTTP/1.0 501 Custom\r\n"));
proxyStub.Start();
var connectionInfo = CreateConnectionInfoWithHttpProxy(proxyEndPoint, serverEndPoint, "anon");
using (var session = new Session(connectionInfo, _serviceFactoryMock.Object))
{
_serviceFactoryMock.Setup(p => p.CreateConnector(connectionInfo))
.Returns(_connectorMock.Object);
_connectorMock.Setup(p => p.Connect(connectionInfo))
.Returns<IConnectionInfo>(c => new HttpConnector().Connect(c));
try
{
session.Connect();
Assert.Fail();
}
catch (ProxyException)
{
}
}
var expectedProxyAuthorizationHeader = CreateProxyAuthorizationHeader(connectionInfo);
Assert.IsNotNull(proxyStub.HttpRequest.Headers.SingleOrDefault(p => p == expectedProxyAuthorizationHeader));
}
}
[TestMethod]
public void ConnectShouldNotWriteProxyAuthorizationToHttpProxyWhenProxyUserNameIsEmpty()
{
var proxyEndPoint = new IPEndPoint(IPAddress.Loopback, 8123);
var serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
using (var proxyStub = new HttpProxyStub(proxyEndPoint))
{
proxyStub.Responses.Add(Encoding.ASCII.GetBytes("HTTP/1.0 501 Custom\r\n"));
proxyStub.Start();
var connectionInfo = CreateConnectionInfoWithHttpProxy(proxyEndPoint, serverEndPoint, string.Empty);
using (var session = new Session(connectionInfo, _serviceFactoryMock.Object))
{
_serviceFactoryMock.Setup(p => p.CreateConnector(connectionInfo))
.Returns(_connectorMock.Object);
_connectorMock.Setup(p => p.Connect(connectionInfo))
.Returns<IConnectionInfo>(c => new HttpConnector().Connect(c));
try
{
session.Connect();
Assert.Fail();
}
catch (ProxyException)
{
}
}
Assert.IsFalse(proxyStub.HttpRequest.Headers.Any(p => p.StartsWith("Proxy-Authorization:")));
}
}
[TestMethod]
public void ConnectShouldNotWriteProxyAuthorizationToHttpProxyWhenProxyUserNameIsNull()
{
var proxyEndPoint = new IPEndPoint(IPAddress.Loopback, 8123);
var serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
using (var proxyStub = new HttpProxyStub(proxyEndPoint))
{
proxyStub.Responses.Add(Encoding.ASCII.GetBytes("HTTP/1.0 501 Custom\r\n"));
proxyStub.Start();
var connectionInfo = CreateConnectionInfoWithHttpProxy(proxyEndPoint, serverEndPoint, null);
using (var session = new Session(connectionInfo, _serviceFactoryMock.Object))
{
_serviceFactoryMock.Setup(p => p.CreateConnector(connectionInfo))
.Returns(_connectorMock.Object);
_connectorMock.Setup(p => p.Connect(connectionInfo))
.Returns<IConnectionInfo>(c => new HttpConnector().Connect(c));
try
{
session.Connect();
Assert.Fail();
}
catch (ProxyException)
{
}
}
Assert.IsFalse(proxyStub.HttpRequest.Headers.Any(p => p.StartsWith("Proxy-Authorization:")));
}
}
private static ConnectionInfo CreateConnectionInfoWithHttpProxy(IPEndPoint proxyEndPoint, IPEndPoint serverEndPoint, string proxyUserName)
{
return new ConnectionInfo(
+13 -393
View File
@@ -1,16 +1,9 @@
using System;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using Renci.SshNet.Connection;
using Renci.SshNet.Messages.Transport;
using Renci.SshNet.Tests.Common;
using Renci.SshNet.Tests.Properties;
namespace Renci.SshNet.Tests.Classes
{
@@ -21,25 +14,28 @@ namespace Renci.SshNet.Tests.Classes
public partial class SessionTest : TestBase
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISocketFactory> _socketFactoryMock;
private Mock<IConnector> _connectorMock;
private Mock<IProtocolVersionExchange> _protocolVersionExchangeMock;
protected override void OnInit()
{
base.OnInit();
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
_socketFactoryMock = new Mock<ISocketFactory>(MockBehavior.Strict);
_connectorMock = new Mock<IConnector>(MockBehavior.Strict);
_protocolVersionExchangeMock = new Mock<IProtocolVersionExchange>(MockBehavior.Strict);
}
[TestMethod]
public void ConstructorShouldThrowArgumentNullExceptionWhenConnectionInfoIsNull()
{
ConnectionInfo connectionInfo = null;
var serviceFactory = new Mock<IServiceFactory>(MockBehavior.Strict).Object;
const ConnectionInfo connectionInfo = null;
try
{
new Session(connectionInfo, serviceFactory);
new Session(connectionInfo, _serviceFactoryMock.Object, _socketFactoryMock.Object);
Assert.Fail();
}
catch (ArgumentNullException ex)
@@ -58,7 +54,7 @@ namespace Renci.SshNet.Tests.Classes
try
{
new Session(connectionInfo, serviceFactory);
new Session(connectionInfo, serviceFactory, _socketFactoryMock.Object);
Assert.Fail();
}
catch (ArgumentNullException ex)
@@ -69,400 +65,24 @@ namespace Renci.SshNet.Tests.Classes
}
[TestMethod]
public void ConnectShouldSkipLinesBeforeProtocolIdentificationString()
public void ConstructorShouldThrowArgumentNullExceptionWhenSocketFactoryIsNull()
{
var serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
var connectionInfo = CreateConnectionInfo(serverEndPoint, TimeSpan.FromSeconds(5));
using (var serverStub = new AsyncSocketListener(serverEndPoint))
{
serverStub.Connected += socket =>
{
socket.Send(Encoding.ASCII.GetBytes("\r\n"));
socket.Send(Encoding.ASCII.GetBytes("WELCOME banner\r\n"));
socket.Send(Encoding.ASCII.GetBytes("SSH-666-SshStub\r\n"));
socket.Shutdown(SocketShutdown.Send);
};
serverStub.Start();
using (var session = new Session(connectionInfo, _serviceFactoryMock.Object))
{
_serviceFactoryMock.Setup(p => p.CreateConnector(connectionInfo))
.Returns(_connectorMock.Object);
_connectorMock.Setup(p => p.Connect(connectionInfo))
.Returns<IConnectionInfo>(c => new DirectConnector().Connect(c));
try
{
session.Connect();
Assert.Fail();
}
catch (SshConnectionException ex)
{
Assert.IsNull(ex.InnerException);
Assert.AreEqual("Server version '666' is not supported.", ex.Message);
Assert.AreEqual("SSH-666-SshStub", connectionInfo.ServerVersion);
}
}
}
}
[TestMethod]
public void ConnectShouldImmediatelySendIdentificationStringWhenConnectionHasBeenEstablised()
{
var serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
var connectionInfo = CreateConnectionInfo(serverEndPoint, TimeSpan.FromSeconds(5));
using (var serverStub = new AsyncSocketListener(serverEndPoint))
{
serverStub.Connected += socket =>
{
var identificationBytes = new byte[2048];
var bytesReceived = socket.Receive(identificationBytes);
if (bytesReceived > 0)
{
var identificationSttring = Encoding.ASCII.GetString(identificationBytes, 0, bytesReceived);
Console.WriteLine("STRING=" + identificationSttring);
Console.WriteLine("DONE");
socket.Send(Encoding.ASCII.GetBytes("\r\n"));
socket.Send(Encoding.ASCII.GetBytes("WELCOME banner\r\n"));
socket.Send(Encoding.ASCII.GetBytes("SSH-666-SshStub\r\n"));
}
socket.Shutdown(SocketShutdown.Send);
};
serverStub.Start();
using (var session = new Session(connectionInfo, _serviceFactoryMock.Object))
{
_serviceFactoryMock.Setup(p => p.CreateConnector(connectionInfo))
.Returns(_connectorMock.Object);
_connectorMock.Setup(p => p.Connect(connectionInfo))
.Returns<IConnectionInfo>(c => new DirectConnector().Connect(c));
try
{
session.Connect();
Assert.Fail();
}
catch (SshConnectionException ex)
{
Assert.IsNull(ex.InnerException);
Assert.AreEqual("Server version '666' is not supported.", ex.Message);
Assert.AreEqual("SSH-666-SshStub", connectionInfo.ServerVersion);
}
}
}
}
[TestMethod]
public void ConnectShouldSupportProtocolIdentificationStringThatDoesNotEndWithCrlf()
{
var serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
var connectionInfo = CreateConnectionInfo(serverEndPoint, TimeSpan.FromSeconds(5));
using (var serverStub = new AsyncSocketListener(serverEndPoint))
{
serverStub.Connected += socket =>
{
socket.Send(Encoding.ASCII.GetBytes("\r\n"));
socket.Send(Encoding.ASCII.GetBytes("WELCOME banner\r\n"));
socket.Send(Encoding.ASCII.GetBytes("SSH-666-SshStub"));
socket.Shutdown(SocketShutdown.Send);
};
serverStub.Start();
using (var session = new Session(connectionInfo, _serviceFactoryMock.Object))
{
_serviceFactoryMock.Setup(p => p.CreateConnector(connectionInfo))
.Returns(_connectorMock.Object);
_connectorMock.Setup(p => p.Connect(connectionInfo))
.Returns<IConnectionInfo>(c => new DirectConnector().Connect(c));
try
{
session.Connect();
Assert.Fail();
}
catch (SshConnectionException ex)
{
Assert.IsNull(ex.InnerException);
Assert.AreEqual("Server version '666' is not supported.", ex.Message);
Assert.AreEqual("SSH-666-SshStub", connectionInfo.ServerVersion);
}
}
}
}
[TestMethod]
public void ConnectShouldThrowSshOperationExceptionWhenServerDoesNotRespondWithinConnectionTimeout()
{
var serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
var timeout = TimeSpan.FromMilliseconds(500);
Socket clientSocket = null;
using (var serverStub = new AsyncSocketListener(serverEndPoint))
{
serverStub.Connected += socket =>
{
socket.Send(Encoding.ASCII.GetBytes("\r\n"));
socket.Send(Encoding.ASCII.GetBytes("WELCOME banner\r\n"));
clientSocket = socket;
};
serverStub.Start();
var connectionInfo = CreateConnectionInfo(serverEndPoint, TimeSpan.FromMilliseconds(500));
using (var session = new Session(connectionInfo, _serviceFactoryMock.Object))
{
_serviceFactoryMock.Setup(p => p.CreateConnector(connectionInfo))
.Returns(_connectorMock.Object);
_connectorMock.Setup(p => p.Connect(connectionInfo))
.Returns<IConnectionInfo>(c => new DirectConnector().Connect(c));
try
{
session.Connect();
Assert.Fail();
}
catch (SshOperationTimeoutException ex)
{
Assert.IsNull(ex.InnerException);
Assert.AreEqual(string.Format(CultureInfo.InvariantCulture, "Socket read operation has timed out after {0:F0} milliseconds.", timeout.TotalMilliseconds), ex.Message);
Assert.IsNotNull(clientSocket);
Assert.IsTrue(clientSocket.Connected);
// shut down socket
clientSocket.Shutdown(SocketShutdown.Send);
}
}
}
}
[TestMethod]
public void ConnectShouldSshConnectionExceptionWhenServerResponseDoesNotContainProtocolIdentificationString()
{
var serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
// response ends with CRLF
using (var serverStub = new AsyncSocketListener(serverEndPoint))
{
serverStub.Connected += socket =>
{
socket.Send(Encoding.ASCII.GetBytes("\r\n"));
socket.Send(Encoding.ASCII.GetBytes("WELCOME banner\r\n"));
socket.Shutdown(SocketShutdown.Send);
};
serverStub.Start();
var connectionInfo = CreateConnectionInfo(serverEndPoint, TimeSpan.FromSeconds(5));
using (var session = new Session(connectionInfo, _serviceFactoryMock.Object))
{
_serviceFactoryMock.Setup(p => p.CreateConnector(connectionInfo))
.Returns(_connectorMock.Object);
_connectorMock.Setup(p => p.Connect(connectionInfo))
.Returns<IConnectionInfo>(c => new DirectConnector().Connect(c));
try
{
session.Connect();
Assert.Fail();
}
catch (SshConnectionException ex)
{
Assert.IsNull(ex.InnerException);
Assert.AreEqual("Server response does not contain SSH protocol identification.", ex.Message);
}
}
}
// response does not end with CRLF
using (var serverStub = new AsyncSocketListener(serverEndPoint))
{
serverStub.Connected += socket =>
{
socket.Send(Encoding.ASCII.GetBytes("\r\n"));
socket.Send(Encoding.ASCII.GetBytes("WELCOME banner"));
socket.Shutdown(SocketShutdown.Send);
};
serverStub.Start();
var connectionInfo = CreateConnectionInfo(serverEndPoint, TimeSpan.FromSeconds(5));
using (var session = new Session(connectionInfo, _serviceFactoryMock.Object))
{
_serviceFactoryMock.Setup(p => p.CreateConnector(connectionInfo))
.Returns(_connectorMock.Object);
_connectorMock.Setup(p => p.Connect(connectionInfo))
.Returns<IConnectionInfo>(c => new DirectConnector().Connect(c));
try
{
session.Connect();
Assert.Fail();
}
catch (SshConnectionException ex)
{
Assert.IsNull(ex.InnerException);
Assert.AreEqual("Server response does not contain SSH protocol identification.", ex.Message);
}
}
}
// last line is empty
using (var serverStub = new AsyncSocketListener(serverEndPoint))
{
serverStub.Connected += socket =>
{
socket.Send(Encoding.ASCII.GetBytes("\r\n"));
socket.Send(Encoding.ASCII.GetBytes("WELCOME banner\r\n"));
socket.Send(Encoding.ASCII.GetBytes("\r\n"));
socket.Shutdown(SocketShutdown.Send);
};
serverStub.Start();
var connectionInfo = CreateConnectionInfo(serverEndPoint, TimeSpan.FromSeconds(5));
using (var session = new Session(connectionInfo, _serviceFactoryMock.Object))
{
_serviceFactoryMock.Setup(p => p.CreateConnector(connectionInfo))
.Returns(_connectorMock.Object);
_connectorMock.Setup(p => p.Connect(connectionInfo))
.Returns<IConnectionInfo>(c => new DirectConnector().Connect(c));
try
{
session.Connect();
Assert.Fail();
}
catch (SshConnectionException ex)
{
Assert.IsNull(ex.InnerException);
Assert.AreEqual("Server response does not contain SSH protocol identification.", ex.Message);
}
}
}
}
[TestMethod]
public void Connect_HostNameInvalid_ShouldThrowSocketExceptionWithErrorCodeHostNotFound()
{
var connectionInfo = new ConnectionInfo("invalid.", 40, "user",
new KeyboardInteractiveAuthenticationMethod("user"));
var session = new Session(connectionInfo, _serviceFactoryMock.Object);
_serviceFactoryMock.Setup(p => p.CreateConnector(connectionInfo))
.Returns(_connectorMock.Object);
_connectorMock.Setup(p => p.Connect(connectionInfo))
.Returns<IConnectionInfo>(c => new DirectConnector().Connect(c));
const ISocketFactory socketFactory = null;
try
{
session.Connect();
new Session(connectionInfo, _serviceFactoryMock.Object, socketFactory);
Assert.Fail();
}
catch (SocketException ex)
catch (ArgumentNullException ex)
{
Assert.AreEqual(ex.ErrorCode, (int)SocketError.HostNotFound);
Assert.IsNull(ex.InnerException);
Assert.AreEqual("socketFactory", ex.ParamName);
}
}
[TestMethod]
public void Connect_ProxyHostNameInvalid_ShouldThrowSocketExceptionWithErrorCodeHostNotFound()
{
var connectionInfo = new ConnectionInfo("localhost", 40, "user", ProxyTypes.Http, "invalid.", 80,
"proxyUser", "proxyPwd", new KeyboardInteractiveAuthenticationMethod("user"));
var session = new Session(connectionInfo, _serviceFactoryMock.Object);
_serviceFactoryMock.Setup(p => p.CreateConnector(connectionInfo))
.Returns(_connectorMock.Object);
_connectorMock.Setup(p => p.Connect(connectionInfo))
.Returns<IConnectionInfo>(c => new HttpConnector().Connect(c));
try
{
session.Connect();
Assert.Fail();
}
catch (SocketException ex)
{
Assert.AreEqual(ex.ErrorCode, (int)SocketError.HostNotFound);
}
}
[TestMethod]
public void DisconnectShouldNotThrowExceptionWhenSocketIsNotConnected()
{
var connectionInfo = new ConnectionInfo("localhost", 6767, Resources.USERNAME,
new KeyboardInteractiveAuthenticationMethod(Resources.USERNAME));
var session = new Session(connectionInfo, _serviceFactoryMock.Object);
_serviceFactoryMock.Setup(p => p.CreateConnector(connectionInfo))
.Returns(_connectorMock.Object);
_connectorMock.Setup(p => p.Connect(connectionInfo))
.Returns<IConnectionInfo>(c => new DirectConnector().Connect(c));
try
{
session.Connect();
Assert.Fail();
}
catch (SocketException)
{
session.Disconnect();
}
}
[TestMethod]
public void DisconnectShouldNotThrowExceptionWhenConnectHasNotBeenInvoked()
{
var connectionInfo = new ConnectionInfo("localhost", 6767, Resources.USERNAME,
new KeyboardInteractiveAuthenticationMethod(Resources.USERNAME));
var session = new Session(connectionInfo, _serviceFactoryMock.Object);
session.Disconnect();
}
[TestMethod]
public void DisposeShouldNotThrowExceptionWhenSocketIsNotConnected()
{
var connectionInfo = new ConnectionInfo("localhost", 6767, Resources.USERNAME,
new KeyboardInteractiveAuthenticationMethod(Resources.USERNAME));
var session = new Session(connectionInfo, _serviceFactoryMock.Object);
_serviceFactoryMock.Setup(p => p.CreateConnector(connectionInfo))
.Returns(_connectorMock.Object);
_connectorMock.Setup(p => p.Connect(connectionInfo))
.Returns<IConnectionInfo>(c => new DirectConnector().Connect(c));
try
{
session.Connect();
Assert.Fail();
}
catch (SocketException)
{
session.Dispose();
}
}
[TestMethod]
public void DisposeShouldNotThrowExceptionWhenConenectHasNotBeenInvoked()
{
var connectionInfo = new ConnectionInfo("localhost", 6767, Resources.USERNAME,
new KeyboardInteractiveAuthenticationMethod(Resources.USERNAME));
var session = new Session(connectionInfo, _serviceFactoryMock.Object);
session.Disconnect();
}
private static ConnectionInfo CreateConnectionInfo(IPEndPoint serverEndPoint, TimeSpan timeout)
{
var connectionInfo = new ConnectionInfo(
@@ -0,0 +1,35 @@
using Moq;
using Renci.SshNet.Connection;
using Renci.SshNet.Tests.Common;
namespace Renci.SshNet.Tests.Classes
{
public abstract class SessionTestBase : TripleATestBase
{
internal Mock<IServiceFactory> _serviceFactoryMock { get; private set; }
internal Mock<ISocketFactory> _socketFactoryMock { get; private set; }
internal Mock<IConnector> _connectorMock { get; private set; }
protected virtual void CreateMocks()
{
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
_socketFactoryMock = new Mock<ISocketFactory>(MockBehavior.Strict);
_connectorMock = new Mock<IConnector>(MockBehavior.Strict);
}
protected virtual void SetupData()
{
}
protected virtual void SetupMocks()
{
}
protected override void Arrange()
{
CreateMocks();
SetupData();
SetupMocks();
}
}
}
@@ -0,0 +1,265 @@
using System;
using System.Net;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Renci.SshNet.Common;
using Renci.SshNet.Messages.Transport;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class SessionTest_ConnectToServerFails : SessionTestBase
{
private ConnectionInfo _connectionInfo;
private Session _session;
private SshConnectionException _connectException;
private SshConnectionException _actualException;
protected override void SetupData()
{
base.SetupData();
var serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
_connectionInfo = CreateConnectionInfo(serverEndPoint, TimeSpan.FromSeconds(5));
_session = new Session(_connectionInfo, _serviceFactoryMock.Object, _socketFactoryMock.Object);
_connectException = new SshConnectionException();
}
protected override void SetupMocks()
{
base.SetupMocks();
_serviceFactoryMock.Setup(p => p.CreateConnector(_connectionInfo, _socketFactoryMock.Object))
.Returns(_connectorMock.Object);
_connectorMock.Setup(p => p.Connect(_connectionInfo))
.Throws(_connectException);
}
protected override void Act()
{
try
{
_session.Connect();
Assert.Fail();
}
catch (SshConnectionException ex)
{
_actualException = ex;
}
}
[TestMethod]
public void ClientVersionIsRenciSshNet()
{
Assert.AreEqual("SSH-2.0-Renci.SshNet.SshClient.0.0.1", _session.ClientVersion);
}
[TestMethod]
public void ConnectionInfoShouldReturnConnectionInfoPassedThroughConstructor()
{
Assert.AreSame(_connectionInfo, _session.ConnectionInfo);
}
public void ConnectShouldHaveRethrownException()
{
Assert.IsNotNull(_actualException);
Assert.AreSame(_connectException, _actualException);
}
[TestMethod]
public void DisconnectShouldNotThrowAnException()
{
_session.Disconnect();
}
[TestMethod]
public void DisposeShouldNotThrowException()
{
_session.Dispose();
}
[TestMethod]
public void IsConnectedShouldReturnFalse()
{
Assert.IsFalse(_session.IsConnected);
}
[TestMethod]
public void SendMessageShouldThrowShhConnectionException()
{
try
{
_session.SendMessage(new IgnoreMessage());
Assert.Fail();
}
catch (SshConnectionException ex)
{
Assert.AreEqual(DisconnectReason.None, ex.DisconnectReason);
Assert.IsNull(ex.InnerException);
Assert.AreEqual("Client not connected.", ex.Message);
}
}
[TestMethod]
public void SessionIdShouldReturnNull()
{
Assert.IsNull(_session.SessionId);
}
[TestMethod]
public void ServerVersionShouldReturnNull()
{
Assert.IsNull(_session.ServerVersion);
}
[TestMethod]
public void WaitOnHandle_WaitOnHandle_WaitHandle_ShouldThrowArgumentNullExceptionWhenWaitHandleIsNull()
{
const WaitHandle waitHandle = null;
try
{
_session.WaitOnHandle(waitHandle);
Assert.Fail();
}
catch (ArgumentNullException ex)
{
Assert.IsNull(ex.InnerException);
Assert.AreEqual("waitHandle", ex.ParamName);
}
}
[TestMethod]
public void WaitOnHandle_WaitOnHandle_WaitHandleAndTimeout_ShouldThrowArgumentNullExceptionWhenWaitHandleIsNull()
{
const WaitHandle waitHandle = null;
var timeout = TimeSpan.FromMinutes(5);
try
{
_session.WaitOnHandle(waitHandle, timeout);
Assert.Fail();
}
catch (ArgumentNullException ex)
{
Assert.IsNull(ex.InnerException);
Assert.AreEqual("waitHandle", ex.ParamName);
}
}
[TestMethod]
public void ISession_TryWait_WaitHandleAndTimeout_ShouldReturnDisconnected()
{
var session = (ISession)_session;
var waitHandle = new ManualResetEvent(false);
var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan);
Assert.AreEqual(WaitResult.Disconnected, result);
}
[TestMethod]
public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnDisconnected()
{
var session = (ISession)_session;
var waitHandle = new ManualResetEvent(false);
Exception exception;
var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out exception);
Assert.AreEqual(WaitResult.Disconnected, result);
Assert.IsNull(exception);
}
[TestMethod]
public void ISession_ConnectionInfoShouldReturnConnectionInfoPassedThroughConstructor()
{
var session = (ISession)_session;
Assert.AreSame(_connectionInfo, session.ConnectionInfo);
}
[TestMethod]
public void ISession_MessageListenerCompletedShouldBeSignaled()
{
var session = (ISession)_session;
Assert.IsNotNull(session.MessageListenerCompleted);
Assert.IsTrue(session.MessageListenerCompleted.WaitOne(0));
}
[TestMethod]
public void ISession_SendMessageShouldThrowShhConnectionException()
{
var session = (ISession)_session;
try
{
session.SendMessage(new IgnoreMessage());
Assert.Fail();
}
catch (SshConnectionException ex)
{
Assert.AreEqual(DisconnectReason.None, ex.DisconnectReason);
Assert.IsNull(ex.InnerException);
Assert.AreEqual("Client not connected.", ex.Message);
}
}
[TestMethod]
public void ISession_TrySendMessageShouldReturnFalse()
{
var session = (ISession)_session;
var actual = session.TrySendMessage(new IgnoreMessage());
Assert.IsFalse(actual);
}
[TestMethod]
public void ISession_WaitOnHandle_WaitHandle_ShouldThrowArgumentNullExceptionWhenWaitHandleIsNull()
{
const WaitHandle waitHandle = null;
var session = (ISession)_session;
try
{
session.WaitOnHandle(waitHandle);
Assert.Fail();
}
catch (ArgumentNullException ex)
{
Assert.IsNull(ex.InnerException);
Assert.AreEqual("waitHandle", ex.ParamName);
}
}
[TestMethod]
public void ISession_WaitOnHandle_WaitHandleAndTimeout_ShouldThrowArgumentNullExceptionWhenWaitHandleIsNull()
{
const WaitHandle waitHandle = null;
var session = (ISession)_session;
try
{
session.WaitOnHandle(waitHandle, Session.InfiniteTimeSpan);
Assert.Fail();
}
catch (ArgumentNullException ex)
{
Assert.IsNull(ex.InnerException);
Assert.AreEqual("waitHandle", ex.ParamName);
}
}
private static ConnectionInfo CreateConnectionInfo(IPEndPoint serverEndPoint, TimeSpan timeout)
{
var connectionInfo = new ConnectionInfo(
serverEndPoint.Address.ToString(),
serverEndPoint.Port,
"eric",
new NoneAuthenticationMethod("eric"));
connectionInfo.Timeout = timeout;
return connectionInfo;
}
}
}
@@ -66,7 +66,7 @@ namespace Renci.SshNet.Tests.Classes
public void ServerVersionShouldNotReturnNull()
{
Assert.IsNotNull(Session.ServerVersion);
Assert.AreEqual("SSH-2.0-SshStub", Session.ServerVersion);
Assert.AreEqual("SSH-2.0-OurServerStub", Session.ServerVersion);
}
[TestMethod]
@@ -253,10 +253,17 @@ namespace Renci.SshNet.Tests.Classes
}
}
[TestMethod]
public void ClientSocketShouldBeConnected()
{
Assert.IsNotNull(ClientSocket);
Assert.IsTrue(ClientSocket.Connected);
}
[TestMethod]
public void CreateConnectorOnServiceFactoryShouldHaveBeenInvokedOnce()
{
ServiceFactoryMock.Verify(p => p.CreateConnector(ConnectionInfo), Times.Once());
ServiceFactoryMock.Verify(p => p.CreateConnector(ConnectionInfo, SocketFactoryMock.Object), Times.Once());
}
[TestMethod]
@@ -22,11 +22,16 @@ namespace Renci.SshNet.Tests.Classes
public abstract class SessionTest_ConnectedBase
{
internal Mock<IServiceFactory> ServiceFactoryMock { get; private set; }
internal Mock<ISocketFactory> SocketFactoryMock { get; private set; }
internal Mock<IConnector> ConnectorMock { get; private set; }
private Mock<IProtocolVersionExchange> _protocolVersionExchangeMock;
private Mock<IKeyExchange> _keyExchangeMock;
private Mock<IClientAuthentication> _clientAuthenticationMock;
private IPEndPoint _serverEndPoint;
private string _keyExchangeAlgorithm;
private bool _authenticationStarted;
private SocketFactory _socketFactory;
protected Random Random { get; private set; }
protected byte[] SessionId { get; private set; }
@@ -39,6 +44,7 @@ namespace Renci.SshNet.Tests.Classes
protected Session Session { get; private set; }
protected Socket ClientSocket { get; private set; }
protected Socket ServerSocket { get; private set; }
internal SshIdentification ServerIdentification { get; private set; }
[TestInitialize]
public void Setup()
@@ -67,6 +73,12 @@ namespace Renci.SshNet.Tests.Classes
Session.Dispose();
Session = null;
}
if (ClientSocket != null && ClientSocket.Connected)
{
ClientSocket.Shutdown(SocketShutdown.Both);
ClientSocket.Dispose();
}
}
protected virtual void SetupData()
@@ -87,8 +99,11 @@ namespace Renci.SshNet.Tests.Classes
DisconnectReceivedRegister = new List<MessageEventArgs<DisconnectMessage>>();
ErrorOccurredRegister = new List<ExceptionEventArgs>();
ServerBytesReceivedRegister = new List<byte[]>();
ServerIdentification = new SshIdentification("2.0", "OurServerStub");
_authenticationStarted = false;
_socketFactory = new SocketFactory();
Session = new Session(ConnectionInfo, ServiceFactoryMock.Object);
Session = new Session(ConnectionInfo, ServiceFactoryMock.Object, SocketFactoryMock.Object);
Session.Disconnected += (sender, args) => DisconnectedRegister.Add(args);
Session.DisconnectReceived += (sender, args) => DisconnectReceivedRegister.Add(args);
Session.ErrorOccured += (sender, args) => ErrorOccurredRegister.Add(args);
@@ -105,60 +120,64 @@ namespace Renci.SshNet.Tests.Classes
{
ServerSocket = socket;
socket.Send(Encoding.ASCII.GetBytes("\r\n"));
socket.Send(Encoding.ASCII.GetBytes("WELCOME banner\r\n"));
socket.Send(Encoding.ASCII.GetBytes("SSH-2.0-SshStub\r\n"));
// Since we're mocking the protocol version exchange, we'll immediately stat KEX upon
// having established the connection instead of when the client has been identified
var keyExchangeInitMessage = new KeyExchangeInitMessage
{
CompressionAlgorithmsClientToServer = new string[0],
CompressionAlgorithmsServerToClient = new string[0],
EncryptionAlgorithmsClientToServer = new string[0],
EncryptionAlgorithmsServerToClient = new string[0],
KeyExchangeAlgorithms = new[] { _keyExchangeAlgorithm },
LanguagesClientToServer = new string[0],
LanguagesServerToClient = new string[0],
MacAlgorithmsClientToServer = new string[0],
MacAlgorithmsServerToClient = new string[0],
ServerHostKeyAlgorithms = new string[0]
};
var keyExchangeInit = keyExchangeInitMessage.GetPacket(8, null);
ServerSocket.Send(keyExchangeInit, 4, keyExchangeInit.Length - 4, SocketFlags.None);
};
var counter = 0;
ServerListener.BytesReceived += (received, socket) =>
{
ServerBytesReceivedRegister.Add(received);
switch (counter++)
if (!_authenticationStarted)
{
case 0:
var keyExchangeInitMessage = new KeyExchangeInitMessage
{
CompressionAlgorithmsClientToServer = new string[0],
CompressionAlgorithmsServerToClient = new string[0],
EncryptionAlgorithmsClientToServer = new string[0],
EncryptionAlgorithmsServerToClient = new string[0],
KeyExchangeAlgorithms = new[] {_keyExchangeAlgorithm},
LanguagesClientToServer = new string[0],
LanguagesServerToClient = new string[0],
MacAlgorithmsClientToServer = new string[0],
MacAlgorithmsServerToClient = new string[0],
ServerHostKeyAlgorithms = new string[0]
};
var keyExchangeInit = keyExchangeInitMessage.GetPacket(8, null);
ServerSocket.Send(keyExchangeInit, 4, keyExchangeInit.Length - 4, SocketFlags.None);
break;
case 1:
var serviceAcceptMessage =
ServiceAcceptMessageBuilder.Create(ServiceName.UserAuthentication)
.Build();
ServerSocket.Send(serviceAcceptMessage, 0, serviceAcceptMessage.Length, SocketFlags.None);
break;
var serviceAcceptMessage = ServiceAcceptMessageBuilder.Create(ServiceName.UserAuthentication)
.Build();
ServerSocket.Send(serviceAcceptMessage, 0, serviceAcceptMessage.Length, SocketFlags.None);
_authenticationStarted = true;
}
};
ServerListener.Start();
ClientSocket = new DirectConnector(_socketFactory).Connect(ConnectionInfo);
}
private void CreateMocks()
{
ServiceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
SocketFactoryMock = new Mock<ISocketFactory>(MockBehavior.Strict);
ConnectorMock = new Mock<IConnector>(MockBehavior.Strict);
_protocolVersionExchangeMock = new Mock<IProtocolVersionExchange>(MockBehavior.Strict);
_keyExchangeMock = new Mock<IKeyExchange>(MockBehavior.Strict);
_clientAuthenticationMock = new Mock<IClientAuthentication>(MockBehavior.Strict);
}
private void SetupMocks()
{
ServiceFactoryMock.Setup(p => p.CreateConnector(ConnectionInfo))
.Returns(ConnectorMock.Object);
ServiceFactoryMock.Setup(p => p.CreateConnector(ConnectionInfo, SocketFactoryMock.Object))
.Returns(ConnectorMock.Object);
ConnectorMock.Setup(p => p.Connect(ConnectionInfo))
.Returns<IConnectionInfo>(c => new DirectConnector().Connect(c));
.Returns(ClientSocket);
ServiceFactoryMock.Setup(p => p.CreateProtocolVersionExchange())
.Returns(_protocolVersionExchangeMock.Object);
_protocolVersionExchangeMock.Setup(p => p.Start(Session.ClientVersion, ClientSocket, ConnectionInfo.Timeout))
.Returns(ServerIdentification);
ServiceFactoryMock.Setup(
p =>
p.CreateKeyExchange(ConnectionInfo.KeyExchangeAlgorithms, new[] { _keyExchangeAlgorithm })).Returns(_keyExchangeMock.Object);
@@ -184,7 +203,6 @@ namespace Renci.SshNet.Tests.Classes
SetupData();
SetupMocks();
ServerListener.Start();
Session.Connect();
}
@@ -5,6 +5,7 @@ using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Renci.SshNet.Common;
using Renci.SshNet.Messages.Transport;
using Renci.SshNet.Tests.Common;
namespace Renci.SshNet.Tests.Classes
{
@@ -49,7 +50,7 @@ namespace Renci.SshNet.Tests.Classes
[TestMethod]
public void ErrorOccurredIsNeverRaised()
{
Assert.AreEqual(0, ErrorOccurredRegister.Count);
Assert.AreEqual(0, ErrorOccurredRegister.Count, ErrorOccurredRegister.AsString());
}
[TestMethod]
@@ -188,5 +189,12 @@ namespace Renci.SshNet.Tests.Classes
Assert.AreEqual(WaitResult.Disconnected, result);
Assert.IsNull(exception);
}
[TestMethod]
public void ClientSocketShouldNotBeConnected()
{
Assert.IsNotNull(ClientSocket);
Assert.IsFalse(ClientSocket.Connected);
}
}
}
@@ -2,6 +2,7 @@
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Renci.SshNet.Messages.Connection;
using Renci.SshNet.Tests.Common;
namespace Renci.SshNet.Tests.Classes
{
@@ -33,7 +34,7 @@ namespace Renci.SshNet.Tests.Classes
[TestMethod]
public void ErrorOccurredShouldNotBeRaised()
{
Assert.AreEqual(0, ErrorOccurredRegister.Count);
Assert.AreEqual(0, ErrorOccurredRegister.Count, ErrorOccurredRegister.AsString());
}
}
}
@@ -22,12 +22,16 @@ namespace Renci.SshNet.Tests.Classes
public class SessionTest_Connected_ServerAndClientDisconnectRace
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISocketFactory> _socketFactoryMock;
private Mock<IConnector> _connectorMock;
private Mock<IProtocolVersionExchange> _protocolVersionExchangeMock;
private Mock<IKeyExchange> _keyExchangeMock;
private Mock<IClientAuthentication> _clientAuthenticationMock;
private IPEndPoint _serverEndPoint;
private string _keyExchangeAlgorithm;
private DisconnectMessage _disconnectMessage;
private SocketFactory _socketFactory;
private bool _authenticationStarted;
protected Random Random { get; private set; }
protected byte[] SessionId { get; private set; }
@@ -38,7 +42,9 @@ namespace Renci.SshNet.Tests.Classes
protected AsyncSocketListener ServerListener { get; private set; }
protected IList<byte[]> ServerBytesReceivedRegister { get; private set; }
protected Session Session { get; private set; }
protected Socket ClientSocket { get; private set; }
protected Socket ServerSocket { get; private set; }
internal SshIdentification ServerIdentification { get; private set; }
private void TearDown()
{
@@ -51,6 +57,12 @@ namespace Renci.SshNet.Tests.Classes
{
Session.Dispose();
}
if (ClientSocket != null && ClientSocket.Connected)
{
ClientSocket.Shutdown(SocketShutdown.Both);
ClientSocket.Dispose();
}
}
protected virtual void SetupData()
@@ -71,76 +83,83 @@ namespace Renci.SshNet.Tests.Classes
DisconnectReceivedRegister = new List<MessageEventArgs<DisconnectMessage>>();
ErrorOccurredRegister = new List<ExceptionEventArgs>();
ServerBytesReceivedRegister = new List<byte[]>();
ServerIdentification = new SshIdentification("2.0", "OurServerStub");
_authenticationStarted = false;
_disconnectMessage = new DisconnectMessage(DisconnectReason.ServiceNotAvailable, "Not today!");
_socketFactory = new SocketFactory();
Session = new Session(ConnectionInfo, _serviceFactoryMock.Object);
Session = new Session(ConnectionInfo, _serviceFactoryMock.Object, _socketFactoryMock.Object);
Session.Disconnected += (sender, args) => DisconnectedRegister.Add(args);
Session.DisconnectReceived += (sender, args) => DisconnectReceivedRegister.Add(args);
Session.ErrorOccured += (sender, args) => ErrorOccurredRegister.Add(args);
Session.KeyExchangeInitReceived += (sender, args) =>
{
var newKeysMessage = new NewKeysMessage();
var newKeys = newKeysMessage.GetPacket(8, null);
ServerSocket.Send(newKeys, 4, newKeys.Length - 4, SocketFlags.None);
};
{
var newKeysMessage = new NewKeysMessage();
var newKeys = newKeysMessage.GetPacket(8, null);
ServerSocket.Send(newKeys, 4, newKeys.Length - 4, SocketFlags.None);
};
ServerListener = new AsyncSocketListener(_serverEndPoint);
ServerListener.Connected += socket =>
{
ServerSocket = socket;
socket.Send(Encoding.ASCII.GetBytes("\r\n"));
socket.Send(Encoding.ASCII.GetBytes("WELCOME banner\r\n"));
socket.Send(Encoding.ASCII.GetBytes("SSH-2.0-SshStub\r\n"));
};
var counter = 0;
ServerListener.BytesReceived += (received, socket) =>
{
ServerBytesReceivedRegister.Add(received);
switch (counter++)
{
case 0:
var keyExchangeInitMessage = new KeyExchangeInitMessage
{
CompressionAlgorithmsClientToServer = new string[0],
CompressionAlgorithmsServerToClient = new string[0],
EncryptionAlgorithmsClientToServer = new string[0],
EncryptionAlgorithmsServerToClient = new string[0],
KeyExchangeAlgorithms = new[] { _keyExchangeAlgorithm },
LanguagesClientToServer = new string[0],
LanguagesServerToClient = new string[0],
MacAlgorithmsClientToServer = new string[0],
MacAlgorithmsServerToClient = new string[0],
ServerHostKeyAlgorithms = new string[0]
};
var keyExchangeInit = keyExchangeInitMessage.GetPacket(8, null);
ServerSocket.Send(keyExchangeInit, 4, keyExchangeInit.Length - 4, SocketFlags.None);
break;
case 1:
ServerSocket = socket;
// Since we're mocking the protocol version exchange, we'll immediately stat KEX upon
// having established the connection instead of when the client has been identified
var keyExchangeInitMessage = new KeyExchangeInitMessage
{
CompressionAlgorithmsClientToServer = new string[0],
CompressionAlgorithmsServerToClient = new string[0],
EncryptionAlgorithmsClientToServer = new string[0],
EncryptionAlgorithmsServerToClient = new string[0],
KeyExchangeAlgorithms = new[] { _keyExchangeAlgorithm },
LanguagesClientToServer = new string[0],
LanguagesServerToClient = new string[0],
MacAlgorithmsClientToServer = new string[0],
MacAlgorithmsServerToClient = new string[0],
ServerHostKeyAlgorithms = new string[0]
};
var keyExchangeInit = keyExchangeInitMessage.GetPacket(8, null);
ServerSocket.Send(keyExchangeInit, 4, keyExchangeInit.Length - 4, SocketFlags.None);
};
ServerListener.BytesReceived += (received, socket) =>
{
ServerBytesReceivedRegister.Add(received);
if (!_authenticationStarted)
{
var serviceAcceptMessage =ServiceAcceptMessageBuilder.Create(ServiceName.UserAuthentication).Build();
ServerSocket.Send(serviceAcceptMessage, 0, serviceAcceptMessage.Length, SocketFlags.None);
break;
}
};
_authenticationStarted = true;
}
};
ServerListener.Start();
ClientSocket = new DirectConnector(_socketFactory).Connect(ConnectionInfo);
}
private void CreateMocks()
{
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
_socketFactoryMock = new Mock<ISocketFactory>(MockBehavior.Strict);
_connectorMock = new Mock<IConnector>(MockBehavior.Strict);
_protocolVersionExchangeMock = new Mock<IProtocolVersionExchange>(MockBehavior.Strict);
_keyExchangeMock = new Mock<IKeyExchange>(MockBehavior.Strict);
_clientAuthenticationMock = new Mock<IClientAuthentication>(MockBehavior.Strict);
}
private void SetupMocks()
{
_serviceFactoryMock.Setup(p => p.CreateConnector(ConnectionInfo))
_serviceFactoryMock.Setup(p => p.CreateConnector(ConnectionInfo, _socketFactoryMock.Object))
.Returns(_connectorMock.Object);
_connectorMock.Setup(p => p.Connect(ConnectionInfo))
.Returns<IConnectionInfo>(c => new DirectConnector().Connect(c));
.Returns(ClientSocket);
_serviceFactoryMock.Setup(p => p.CreateProtocolVersionExchange())
.Returns(_protocolVersionExchangeMock.Object);
_protocolVersionExchangeMock.Setup(p => p.Start(Session.ClientVersion, ClientSocket, ConnectionInfo.Timeout))
.Returns(ServerIdentification);
_serviceFactoryMock.Setup(
p =>
p.CreateKeyExchange(ConnectionInfo.KeyExchangeAlgorithms, new[] { _keyExchangeAlgorithm })).Returns(_keyExchangeMock.Object);
@@ -164,7 +183,6 @@ namespace Renci.SshNet.Tests.Classes
SetupData();
SetupMocks();
ServerListener.Start();
Session.Connect();
}
@@ -6,6 +6,7 @@ using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Renci.SshNet.Common;
using Renci.SshNet.Messages.Transport;
using Renci.SshNet.Tests.Common;
namespace Renci.SshNet.Tests.Classes
{
@@ -70,7 +71,7 @@ namespace Renci.SshNet.Tests.Classes
[TestMethod]
public void ErrorOccurredIsNeverRaised()
{
Assert.AreEqual(0, ErrorOccurredRegister.Count);
Assert.AreEqual(0, ErrorOccurredRegister.Count, ErrorOccurredRegister.AsString());
}
[TestMethod]
@@ -6,6 +6,7 @@ using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Renci.SshNet.Common;
using Renci.SshNet.Messages.Transport;
using Renci.SshNet.Tests.Common;
namespace Renci.SshNet.Tests.Classes
{
@@ -73,7 +74,7 @@ namespace Renci.SshNet.Tests.Classes
[TestMethod]
public void ErrorOccurredIsNeverRaised()
{
Assert.AreEqual(0, ErrorOccurredRegister.Count);
Assert.AreEqual(0, ErrorOccurredRegister.Count, ErrorOccurredRegister.AsString());
}
[TestMethod]
@@ -5,6 +5,7 @@ using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Renci.SshNet.Common;
using Renci.SshNet.Messages.Transport;
using Renci.SshNet.Tests.Common;
namespace Renci.SshNet.Tests.Classes
{
@@ -66,7 +67,7 @@ namespace Renci.SshNet.Tests.Classes
[TestMethod]
public void ErrorOccurredIsRaisedOnce()
{
Assert.AreEqual(1, ErrorOccurredRegister.Count);
Assert.AreEqual(1, ErrorOccurredRegister.Count, ErrorOccurredRegister.AsString());
var errorOccurred = ErrorOccurredRegister[0];
Assert.IsNotNull(errorOccurred);
@@ -4,34 +4,27 @@ using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using Renci.SshNet.Connection;
using Renci.SshNet.Messages.Transport;
using Renci.SshNet.Tests.Common;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class SessionTest_NotConnected
public class SessionTest_NotConnected : SessionTestBase
{
private ConnectionInfo _connectionInfo;
private IServiceFactory _serviceFactory;
private Session _session;
[TestInitialize]
public void Setup()
{
Arrange();
Act();
}
protected void Arrange()
protected override void SetupData()
{
var serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
_connectionInfo = CreateConnectionInfo(serverEndPoint, TimeSpan.FromSeconds(5));
_serviceFactory = new Mock<IServiceFactory>(MockBehavior.Strict).Object;
}
protected void Act()
protected override void Act()
{
_session = new Session(_connectionInfo, _serviceFactory);
_session = new Session(_connectionInfo, _serviceFactoryMock.Object, _socketFactoryMock.Object);
}
[TestMethod]
@@ -46,6 +39,18 @@ namespace Renci.SshNet.Tests.Classes
Assert.AreSame(_connectionInfo, _session.ConnectionInfo);
}
[TestMethod]
public void DisconnectShouldNotThrowException()
{
_session.Disconnect();
}
[TestMethod]
public void DisposeShouldNotThrowException()
{
_session.Dispose();
}
[TestMethod]
public void IsConnectedShouldReturnFalse()
{
@@ -1,7 +1,6 @@
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
@@ -15,13 +14,17 @@ namespace Renci.SshNet.Tests.Classes
public class SessionTest_SocketConnected_BadPacketAndDispose
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISocketFactory> _socketFactoryMock;
private Mock<IConnector> _connectorMock;
private Mock<IProtocolVersionExchange> _protocolVersionExchangeMock;
private ConnectionInfo _connectionInfo;
private Session _session;
private AsyncSocketListener _serverListener;
private IPEndPoint _serverEndPoint;
private Socket _serverSocket;
private Socket _clientSocket;
private SshConnectionException _actualException;
private SocketFactory _socketFactory;
[TestInitialize]
public void Setup()
@@ -42,7 +45,9 @@ namespace Renci.SshNet.Tests.Classes
protected void CreateMocks()
{
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
_socketFactoryMock = new Mock<ISocketFactory>(MockBehavior.Strict);
_connectorMock = new Mock<IConnector>(MockBehavior.Strict);
_protocolVersionExchangeMock = new Mock<IProtocolVersionExchange>(MockBehavior.Strict);
}
protected void SetupData()
@@ -55,30 +60,37 @@ namespace Renci.SshNet.Tests.Classes
new PasswordAuthenticationMethod("user", "password"));
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(200);
_actualException = null;
_socketFactory = new SocketFactory();
_serverListener = new AsyncSocketListener(_serverEndPoint);
_serverListener.Connected += (socket) =>
{
_serverSocket = socket;
socket.Send(Encoding.ASCII.GetBytes("\r\n"));
socket.Send(Encoding.ASCII.GetBytes("WELCOME banner\r\n"));
socket.Send(Encoding.ASCII.GetBytes("SSH-2.0-SshStub\r\n"));
};
_serverListener.BytesReceived += (received, socket) =>
{
// Since we're mocking the protocol version exchange, we can immediately send the bad
// packet upon establishing the connection
var badPacket = new byte[] { 0x0a, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05 };
_serverSocket.Send(badPacket, 0, badPacket.Length, SocketFlags.None);
_serverSocket.Shutdown(SocketShutdown.Send);
};
_serverListener.Start();
_session = new Session(_connectionInfo, _serviceFactoryMock.Object, _socketFactoryMock.Object);
_clientSocket = new DirectConnector(_socketFactory).Connect(_connectionInfo);
}
protected void SetupMocks()
{
_serviceFactoryMock.Setup(p => p.CreateConnector(_connectionInfo))
_serviceFactoryMock.Setup(p => p.CreateConnector(_connectionInfo, _socketFactoryMock.Object))
.Returns(_connectorMock.Object);
_connectorMock.Setup(p => p.Connect(_connectionInfo))
.Returns<IConnectionInfo>(c => new DirectConnector().Connect(c));
.Returns(_clientSocket);
_serviceFactoryMock.Setup(p => p.CreateProtocolVersionExchange())
.Returns(_protocolVersionExchangeMock.Object);
_protocolVersionExchangeMock.Setup(p => p.Start(_session.ClientVersion, _clientSocket, _connectionInfo.Timeout))
.Returns(new SshIdentification("2.0", "XXX"));
}
protected void Arrange()
@@ -86,15 +98,13 @@ namespace Renci.SshNet.Tests.Classes
CreateMocks();
SetupData();
SetupMocks();
_serverListener.Start();
}
protected virtual void Act()
{
try
{
using (_session = new Session(_connectionInfo, _serviceFactoryMock.Object))
{
_session.Connect();
}
@@ -0,0 +1,19 @@
using Moq;
using Renci.SshNet.Sftp;
namespace Renci.SshNet.Tests.Classes
{
public abstract class SftpClientTestBase : BaseClientTestBase
{
internal Mock<ISftpResponseFactory> _sftpResponseFactoryMock { get; private set; }
internal Mock<ISftpSession> _sftpSessionMock { get; private set; }
protected override void CreateMocks()
{
base.CreateMocks();
_sftpResponseFactoryMock = new Mock<ISftpResponseFactory>(MockBehavior.Strict);
_sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
}
}
}
@@ -4,59 +4,35 @@ using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using Renci.SshNet.Connection;
using Renci.SshNet.Security;
using Renci.SshNet.Sftp;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class SftpClientTest_Connect_SftpSessionConnectFailure
public class SftpClientTest_Connect_SftpSessionConnectFailure : SftpClientTestBase
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private Mock<ISftpResponseFactory> _sftpResponseFactoryMock;
private Mock<ISftpSession> _sftpSessionMock;
private ConnectionInfo _connectionInfo;
private ApplicationException _sftpSessionConnectionException;
private SftpClient _sftpClient;
private ApplicationException _actualException;
[TestInitialize]
public void Setup()
{
Arrange();
Act();
}
private void Arrange()
{
SetupData();
CreateMocks();
SetupMocks();
_sftpClient = new SftpClient(_connectionInfo, false, _serviceFactoryMock.Object);
}
private void SetupData()
protected override void SetupData()
{
_connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth"));
_sftpSessionConnectionException = new ApplicationException();
}
private void CreateMocks()
{
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
_sftpResponseFactoryMock = new Mock<ISftpResponseFactory>(MockBehavior.Strict);
_sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
}
private void SetupMocks()
protected override void SetupMocks()
{
var sequence = new MockSequence();
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo))
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence)
.Setup(p => p.Connect());
@@ -75,7 +51,14 @@ namespace Renci.SshNet.Tests.Classes
.Setup(p => p.Dispose());
}
private void Act()
protected override void Arrange()
{
base.Arrange();
_sftpClient = new SftpClient(_connectionInfo, false, _serviceFactoryMock.Object);
}
protected override void Act()
{
try
{
@@ -6,44 +6,30 @@ using Renci.SshNet.Sftp;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class SftpClientTest_Dispose_Connected
public class SftpClientTest_Dispose_Connected : SftpClientTestBase
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private Mock<ISftpResponseFactory> _sftpResponseFactoryMock;
private Mock<ISftpSession> _sftpSessionMock;
private SftpClient _sftpClient;
private ConnectionInfo _connectionInfo;
private int _operationTimeout;
[TestInitialize]
public void Setup()
protected override void SetupData()
{
Arrange();
Act();
}
[TestCleanup]
public void Cleanup()
{
}
protected void Arrange()
{
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
_sftpResponseFactoryMock = new Mock<ISftpResponseFactory>(MockBehavior.Strict);
_sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
_connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth"));
_operationTimeout = new Random().Next(1000, 10000);
_sftpClient = new SftpClient(_connectionInfo, false, _serviceFactoryMock.Object);
_sftpClient.OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout);
}
protected override void SetupMocks()
{
var sequence = new MockSequence();
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo))
.Returns(_sessionMock.Object);
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence).Setup(p => p.Connect());
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSftpResponseFactory())
@@ -55,11 +41,16 @@ namespace Renci.SshNet.Tests.Classes
_sessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting());
_sftpSessionMock.InSequence(sequence).Setup(p => p.Dispose());
_sessionMock.InSequence(sequence).Setup(p => p.Dispose());
}
protected override void Arrange()
{
base.Arrange();
_sftpClient.Connect();
}
protected void Act()
protected override void Act()
{
_sftpClient.Dispose();
}
@@ -78,10 +69,17 @@ namespace Renci.SshNet.Tests.Classes
Times.Once);
}
[TestMethod]
public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once);
}
[TestMethod]
public void CreateSessionOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo), Times.Once);
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object),
Times.Once);
}
[TestMethod]
@@ -6,40 +6,31 @@ using Renci.SshNet.Sftp;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class SftpClientTest_Dispose_Disconnected
public class SftpClientTest_Dispose_Disconnected : SftpClientTestBase
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private Mock<ISftpResponseFactory> _sftpResponseFactoryMock;
private Mock<ISftpSession> _sftpSessionMock;
private SftpClient _sftpClient;
private ConnectionInfo _connectionInfo;
private int _operationTimeout;
[TestInitialize]
public void Setup()
protected override void SetupData()
{
Arrange();
Act();
}
protected void Arrange()
{
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
_sftpResponseFactoryMock = new Mock<ISftpResponseFactory>(MockBehavior.Strict);
_sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
_connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth"));
_operationTimeout = new Random().Next(1000, 10000);
_sftpClient = new SftpClient(_connectionInfo, false, _serviceFactoryMock.Object);
_sftpClient.OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout);
}
protected override void SetupMocks()
{
var sequence = new MockSequence();
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo))
.Returns(_sessionMock.Object);
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence).Setup(p => p.Connect());
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSftpResponseFactory())
@@ -51,12 +42,17 @@ namespace Renci.SshNet.Tests.Classes
_sessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting());
_sftpSessionMock.InSequence(sequence).Setup(p => p.Dispose());
_sessionMock.InSequence(sequence).Setup(p => p.Dispose());
}
protected override void Arrange()
{
base.Arrange();
_sftpClient.Connect();
_sftpClient.Disconnect();
}
protected void Act()
protected override void Act()
{
_sftpClient.Dispose();
}
@@ -75,10 +71,17 @@ namespace Renci.SshNet.Tests.Classes
Times.Once);
}
[TestMethod]
public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once);
}
[TestMethod]
public void CreateSessionOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo), Times.Once);
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object),
Times.Once);
}
[TestMethod]
@@ -6,44 +6,30 @@ using Renci.SshNet.Sftp;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class SftpClientTest_Dispose_Disposed
public class SftpClientTest_Dispose_Disposed : SftpClientTestBase
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private Mock<ISftpResponseFactory> _sftpResponseFactoryMock;
private Mock<ISftpSession> _sftpSessionMock;
private SftpClient _sftpClient;
private ConnectionInfo _connectionInfo;
private int _operationTimeout;
[TestInitialize]
public void Setup()
protected override void SetupData()
{
Arrange();
Act();
}
[TestCleanup]
public void Cleanup()
{
}
protected void Arrange()
{
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
_sftpResponseFactoryMock = new Mock<ISftpResponseFactory>(MockBehavior.Strict);
_sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
_connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth"));
_operationTimeout = new Random().Next(1000, 10000);
_sftpClient = new SftpClient(_connectionInfo, false, _serviceFactoryMock.Object);
_sftpClient.OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout);
}
protected override void SetupMocks()
{
var sequence = new MockSequence();
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo))
.Returns(_sessionMock.Object);
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence).Setup(p => p.Connect());
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSftpResponseFactory())
@@ -55,12 +41,17 @@ namespace Renci.SshNet.Tests.Classes
_sessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting());
_sftpSessionMock.InSequence(sequence).Setup(p => p.Dispose());
_sessionMock.InSequence(sequence).Setup(p => p.Dispose());
}
protected override void Arrange()
{
base.Arrange();
_sftpClient.Connect();
_sftpClient.Dispose();
}
protected void Act()
protected override void Act()
{
_sftpClient.Dispose();
}
@@ -79,10 +70,17 @@ namespace Renci.SshNet.Tests.Classes
Times.Once);
}
[TestMethod]
public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once);
}
[TestMethod]
public void CreateSessionOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo), Times.Once);
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object),
Times.Once);
}
[TestMethod]
@@ -6,54 +6,49 @@ using Renci.SshNet.Sftp;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class SftpClientTest_Finalize_Connected
public class SftpClientTest_Finalize_Connected : SftpClientTestBase
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private Mock<ISftpResponseFactory> _sftpResponseFactoryMock;
private Mock<ISftpSession> _sftpSessionMock;
private SftpClient _sftpClient;
private ConnectionInfo _connectionInfo;
private int _operationTimeout;
private WeakReference _sftpClientWeakRefence;
[TestInitialize]
public void Setup()
protected override void SetupData()
{
Arrange();
Act();
}
protected void Arrange()
{
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Loose);
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
_sftpResponseFactoryMock = new Mock<ISftpResponseFactory>(MockBehavior.Strict);
_sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
_connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth"));
_operationTimeout = new Random().Next(1000, 10000);
_sftpClient = new SftpClient(_connectionInfo, false, _serviceFactoryMock.Object);
_sftpClient.OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout);
_sftpClientWeakRefence = new WeakReference(_sftpClient);
}
_serviceFactoryMock.Setup(p => p.CreateSession(_connectionInfo))
.Returns(_sessionMock.Object);
protected override void SetupMocks()
{
_serviceFactoryMock.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.Setup(p => p.Connect());
_serviceFactoryMock.Setup(p => p.CreateSftpResponseFactory())
.Returns(_sftpResponseFactoryMock.Object);
_serviceFactoryMock.Setup(p => p.CreateSftpSession(_sessionMock.Object, _operationTimeout, _connectionInfo.Encoding, _sftpResponseFactoryMock.Object))
.Returns(_sftpSessionMock.Object);
_sftpSessionMock.Setup(p => p.Connect());
}
protected override void Arrange()
{
base.Arrange();
_sftpClient.Connect();
_sftpClient = null;
// we need to dereference all other mocks as they might otherwise hold the target alive
_sessionMock = null;
_connectionInfo = null;
_serviceFactoryMock = null;
// We need to dereference all mocks as they might otherwise hold the target alive
//(through recorded invocations?)
CreateMocks();
}
protected void Act()
protected override void Act()
{
GC.Collect();
GC.WaitForPendingFinalizers();
@@ -62,13 +57,25 @@ namespace Renci.SshNet.Tests.Classes
[TestMethod]
public void DisconnectOnSftpSessionShouldNeverBeInvoked()
{
// Since we recreated the mocks, this test has no value
// We'll leaving ths test just in case we have a solution that does not require us
// to recreate the mocks
_sftpSessionMock.Verify(p => p.Disconnect(), Times.Never);
}
[TestMethod]
public void DisposeOnSftpSessionShouldNeverBeInvoked()
{
// Since we recreated the mocks, this test has no value
// We'll leaving ths test just in case we have a solution that does not require us
// to recreate the mocks
_sftpSessionMock.Verify(p => p.Dispose(), Times.Never);
}
[TestMethod]
public void SftpClientShouldHaveBeenFinalized()
{
Assert.IsNull(_sftpClientWeakRefence.Target);
}
}
}
@@ -8,11 +8,8 @@ using Renci.SshNet.Common;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class
SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSizeAndTerminalModes_Connected
public class SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSizeAndTerminalModes_Connected : BaseClientTestBase
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private SshClient _sshClient;
private ConnectionInfo _connectionInfo;
private string _terminalName;
@@ -25,14 +22,7 @@ namespace Renci.SshNet.Tests.Classes
private ShellStream _expected;
private ShellStream _actual;
[TestInitialize]
public void Setup()
{
Arrange();
Act();
}
private void SetupData()
protected override void SetupData()
{
var random = new Random();
@@ -49,18 +39,15 @@ namespace Renci.SshNet.Tests.Classes
_expected = CreateShellStream();
}
private void CreateMocks()
{
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
}
private void SetupMocks()
protected override void SetupMocks()
{
var sequence = new MockSequence();
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo))
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence)
.Setup(p => p.Connect());
@@ -76,17 +63,15 @@ namespace Renci.SshNet.Tests.Classes
.Returns(_expected);
}
private void Arrange()
protected override void Arrange()
{
SetupData();
CreateMocks();
SetupMocks();
base.Arrange();
_sshClient = new SshClient(_connectionInfo, false, _serviceFactoryMock.Object);
_sshClient.Connect();
}
protected void Act()
protected override void Act()
{
_actual = _sshClient.CreateShellStream(_terminalName,
_widthColumns,
@@ -8,10 +8,8 @@ using Renci.SshNet.Common;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSize_Connected
public class SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSize_Connected : BaseClientTestBase
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private SshClient _sshClient;
private ConnectionInfo _connectionInfo;
private string _terminalName;
@@ -23,14 +21,7 @@ namespace Renci.SshNet.Tests.Classes
private ShellStream _expected;
private ShellStream _actual;
[TestInitialize]
public void Setup()
{
Arrange();
Act();
}
private void SetupData()
protected override void SetupData()
{
var random = new Random();
@@ -46,18 +37,15 @@ namespace Renci.SshNet.Tests.Classes
_expected = CreateShellStream();
}
private void CreateMocks()
{
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
}
private void SetupMocks()
protected override void SetupMocks()
{
var sequence = new MockSequence();
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo))
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence)
.Setup(p => p.Connect());
@@ -73,17 +61,15 @@ namespace Renci.SshNet.Tests.Classes
.Returns(_expected);
}
private void Arrange()
protected override void Arrange()
{
SetupData();
CreateMocks();
SetupMocks();
base.Arrange();
_sshClient = new SshClient(_connectionInfo, false, _serviceFactoryMock.Object);
_sshClient.Connect();
}
protected void Act()
protected override void Act()
{
_actual = _sshClient.CreateShellStream(_terminalName,
_widthColumns,
@@ -5,42 +5,37 @@ using Moq;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class SshClientTest_Disconnect_ForwardedPortStarted
public class SshClientTest_Disconnect_ForwardedPortStarted : BaseClientTestBase
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private Mock<ForwardedPort> _forwardedPortMock;
private SshClient _sshClient;
private ConnectionInfo _connectionInfo;
[TestInitialize]
public void Setup()
{
Arrange();
Act();
}
[TestCleanup]
public void Cleanup()
{
}
protected void Arrange()
protected override void SetupData()
{
_connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth"));
}
protected override void SetupMocks()
{
var sequence = new MockSequence();
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
_forwardedPortMock = new Mock<ForwardedPort>(MockBehavior.Strict);
_serviceFactoryMock.InSequence(sequence).Setup(p => p.CreateSession(_connectionInfo)).Returns(_sessionMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence).Setup(p => p.Connect());
_forwardedPortMock.InSequence(sequence).Setup(p => p.Start());
_sessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting());
_forwardedPortMock.InSequence(sequence).Setup(p => p.Stop());
_sessionMock.InSequence(sequence).Setup(p => p.Dispose());
}
protected override void Arrange()
{
base.Arrange();
_sshClient = new SshClient(_connectionInfo, false, _serviceFactoryMock.Object);
_sshClient.Connect();
@@ -49,7 +44,7 @@ namespace Renci.SshNet.Tests.Classes
_forwardedPortMock.Object.Start();
}
protected void Act()
protected override void Act()
{
_sshClient.Disconnect();
}
@@ -4,51 +4,55 @@ using Moq;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class SshClientTest_Dispose_Connected
public class SshClientTest_Dispose_Connected : BaseClientTestBase
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private SshClient _sshClient;
private ConnectionInfo _connectionInfo;
[TestInitialize]
public void Setup()
{
Arrange();
Act();
}
[TestCleanup]
public void Cleanup()
{
}
protected void Arrange()
protected override void SetupData()
{
_connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth"));
}
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
protected override void SetupMocks()
{
var sequence = new MockSequence();
_serviceFactoryMock.InSequence(sequence).Setup(p => p.CreateSession(_connectionInfo)).Returns(_sessionMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence).Setup(p => p.Connect());
_sessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting());
_sessionMock.InSequence(sequence).Setup(p => p.Dispose());
}
protected override void Arrange()
{
base.Arrange();
_sshClient = new SshClient(_connectionInfo, false, _serviceFactoryMock.Object);
_sshClient.Connect();
}
protected void Act()
protected override void Act()
{
_sshClient.Dispose();
}
[TestMethod]
public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once);
}
[TestMethod]
public void CreateSessionOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo), Times.Once);
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object),
Times.Once);
}
[TestMethod]
@@ -4,52 +4,56 @@ using Moq;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class SshClientTest_Dispose_Disconnected
public class SshClientTest_Dispose_Disconnected : BaseClientTestBase
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private SshClient _sshClient;
private ConnectionInfo _connectionInfo;
[TestInitialize]
public void Setup()
{
Arrange();
Act();
}
[TestCleanup]
public void Cleanup()
{
}
protected void Arrange()
protected override void SetupData()
{
_connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth"));
}
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
protected override void SetupMocks()
{
var sequence = new MockSequence();
_serviceFactoryMock.InSequence(sequence).Setup(p => p.CreateSession(_connectionInfo)).Returns(_sessionMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence).Setup(p => p.Connect());
_sessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting());
_sessionMock.InSequence(sequence).Setup(p => p.Dispose());
}
protected override void Arrange()
{
base.Arrange();
_sshClient = new SshClient(_connectionInfo, false, _serviceFactoryMock.Object);
_sshClient.Connect();
_sshClient.Disconnect();
}
protected void Act()
protected override void Act()
{
_sshClient.Dispose();
}
[TestMethod]
public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once);
}
[TestMethod]
public void CreateSessionOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo), Times.Once);
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object),
Times.Once);
}
[TestMethod]
@@ -4,52 +4,56 @@ using Moq;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class SshClientTest_Dispose_Disposed
public class SshClientTest_Dispose_Disposed : BaseClientTestBase
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private SshClient _sshClient;
private ConnectionInfo _connectionInfo;
[TestInitialize]
public void Setup()
{
Arrange();
Act();
}
[TestCleanup]
public void Cleanup()
{
}
protected void Arrange()
protected override void SetupData()
{
_connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth"));
}
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
protected override void SetupMocks()
{
var sequence = new MockSequence();
_serviceFactoryMock.InSequence(sequence).Setup(p => p.CreateSession(_connectionInfo)).Returns(_sessionMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence).Setup(p => p.Connect());
_sessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting());
_sessionMock.InSequence(sequence).Setup(p => p.Dispose());
}
protected override void Arrange()
{
base.Arrange();
_sshClient = new SshClient(_connectionInfo, false, _serviceFactoryMock.Object);
_sshClient.Connect();
_sshClient.Dispose();
}
protected void Act()
protected override void Act()
{
_sshClient.Dispose();
}
[TestMethod]
public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once);
}
[TestMethod]
public void CreateSessionOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo), Times.Once);
_serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object),
Times.Once);
}
[TestMethod]
@@ -6,42 +6,44 @@ using Moq;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class SshClientTest_Dispose_ForwardedPortStarted
public class SshClientTest_Dispose_ForwardedPortStarted : BaseClientTestBase
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private Mock<ForwardedPort> _forwardedPortMock;
private SshClient _sshClient;
private ConnectionInfo _connectionInfo;
[TestInitialize]
public void Setup()
protected override void CreateMocks()
{
Arrange();
Act();
base.CreateMocks();
_forwardedPortMock = new Mock<ForwardedPort>(MockBehavior.Strict);
}
[TestCleanup]
public void Cleanup()
{
}
protected void Arrange()
protected override void SetupData()
{
_connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth"));
}
protected override void SetupMocks()
{
var sequence = new MockSequence();
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
_forwardedPortMock = new Mock<ForwardedPort>(MockBehavior.Strict);
_serviceFactoryMock.InSequence(sequence).Setup(p => p.CreateSession(_connectionInfo)).Returns(_sessionMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSocketFactory())
.Returns(_socketFactoryMock.Object);
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence).Setup(p => p.Connect());
_forwardedPortMock.InSequence(sequence).Setup(p => p.Start());
_sessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting());
_forwardedPortMock.InSequence(sequence).Setup(p => p.Stop());
_sessionMock.InSequence(sequence).Setup(p => p.Dispose());
}
protected override void Arrange()
{
base.Arrange();
_sshClient = new SshClient(_connectionInfo, false, _serviceFactoryMock.Object);
_sshClient.Connect();
@@ -50,7 +52,7 @@ namespace Renci.SshNet.Tests.Classes
_forwardedPortMock.Object.Start();
}
protected void Act()
protected override void Act()
{
_sshClient.Dispose();
}
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
@@ -12,9 +13,11 @@ namespace Renci.SshNet.Tests.Common
{
private readonly IPEndPoint _endPoint;
private readonly ManualResetEvent _acceptCallbackDone;
private List<Socket> _connectedClients;
private Socket _listener;
private Thread _receiveThread;
private bool _started;
private object _syncLock;
public delegate void BytesReceivedHandler(byte[] bytesReceived, Socket socket);
public delegate void ConnectedHandler(Socket socket);
@@ -27,6 +30,8 @@ namespace Renci.SshNet.Tests.Common
{
_endPoint = endPoint;
_acceptCallbackDone = new ManualResetEvent(false);
_connectedClients = new List<Socket>();
_syncLock = new object();
ShutdownRemoteCommunicationSocket = true;
}
@@ -56,11 +61,31 @@ namespace Renci.SshNet.Tests.Common
public void Stop()
{
_started = false;
lock (_syncLock)
{
foreach (var connectedClient in _connectedClients)
{
try
{
connectedClient.Shutdown(SocketShutdown.Send);
}
catch (Exception ex)
{
Console.Error.WriteLine("[{0}] Failure shutting down socket: {1}",
typeof(AsyncSocketListener).FullName,
ex);
}
DrainSocket(connectedClient);
}
}
if (_listener != null)
{
_listener.Dispose();
_listener = null;
}
if (_receiveThread != null)
{
_receiveThread.Join();
@@ -87,15 +112,23 @@ namespace Renci.SshNet.Tests.Common
private void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue.
// Signal the main thread to continue
_acceptCallbackDone.Set();
// Get the socket that handles the client request.
var listener = (Socket)ar.AsyncState;
// Get the socket that listens for inbound connections
var listener = (Socket) ar.AsyncState;
// Get the socket that handles the client request
var handler = listener.EndAccept(ar);
// Signal new connection
SignalConnected(handler);
// Register client socket
_connectedClients.Add(handler);
try
{
var handler = listener.EndAccept(ar);
SignalConnected(handler);
var state = new SocketStateObject(handler);
handler.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, ReadCallback, state);
}
@@ -109,7 +142,7 @@ namespace Renci.SshNet.Tests.Common
private void ReadCallback(IAsyncResult ar)
{
// Retrieve the state object and the handler socket
// from the asynchronous state object.
// from the asynchronous state object
var state = (SocketStateObject) ar.AsyncState;
var handler = state.Socket;
@@ -132,8 +165,6 @@ namespace Renci.SshNet.Tests.Common
var bytesReceived = new byte[bytesRead];
Array.Copy(state.Buffer, bytesReceived, bytesRead);
SignalBytesReceived(bytesReceived, handler);
// prepare to receive more bytes
handler.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, ReadCallback, state);
}
else
@@ -142,8 +173,13 @@ namespace Renci.SshNet.Tests.Common
if (ShutdownRemoteCommunicationSocket)
{
handler.Shutdown(SocketShutdown.Both);
handler.Close();
lock (_syncLock)
{
handler.Shutdown(SocketShutdown.Send);
handler.Close();
_connectedClients.Remove(handler);
}
}
}
}
@@ -169,6 +205,30 @@ namespace Renci.SshNet.Tests.Common
subscribers(client);
}
private static void DrainSocket(Socket socket)
{
var buffer = new byte[128];
try
{
while (true && socket.Connected)
{
var bytesRead = socket.Receive(buffer);
if (bytesRead == 0)
{
break;
}
}
}
catch (SocketException ex)
{
Console.Error.WriteLine("[{0}] Failure draining socket ({1}): {2}",
typeof(AsyncSocketListener).FullName,
ex.SocketErrorCode.ToString("G"),
ex);
}
}
private class SocketStateObject
{
public Socket Socket { get; private set; }
@@ -0,0 +1,29 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Renci.SshNet.Tests.Common
{
public abstract class TripleATestBase
{
[TestInitialize]
public void Init()
{
Arrange();
Act();
}
[TestCleanup]
public void Cleanup()
{
TearDown();
}
protected virtual void TearDown()
{
}
protected abstract void Arrange();
protected abstract void Act();
}
}
+1 -1
View File
@@ -457,7 +457,7 @@ namespace Renci.SshNet
private ISession CreateAndConnectSession()
{
var session = _serviceFactory.CreateSession(ConnectionInfo);
var session = _serviceFactory.CreateSession(ConnectionInfo, _serviceFactory.CreateSocketFactory());
session.HostKeyReceived += Session_HostKeyReceived;
session.ErrorOccured += Session_ErrorOccured;
+53 -11
View File
@@ -9,6 +9,16 @@ namespace Renci.SshNet.Connection
{
internal abstract class ConnectorBase : IConnector
{
protected ConnectorBase(ISocketFactory socketFactory)
{
if (socketFactory == null)
throw new ArgumentNullException("socketFactory");
SocketFactory = socketFactory;
}
internal ISocketFactory SocketFactory { get; private set; }
public abstract Socket Connect(IConnectionInfo connectionInfo);
/// <summary>
@@ -26,18 +36,35 @@ namespace Renci.SshNet.Connection
DiagnosticAbstraction.Log(string.Format("Initiating connection to '{0}:{1}'.", host, port));
var socket = SocketAbstraction.Connect(ep, timeout);
var socket = SocketFactory.Create(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
const int socketBufferSize = 2 * Session.MaximumSshPacketSize;
socket.SendBufferSize = socketBufferSize;
socket.ReceiveBufferSize = socketBufferSize;
return socket;
try
{
SocketAbstraction.Connect(socket, ep, timeout);
const int socketBufferSize = 2 * Session.MaximumSshPacketSize;
socket.SendBufferSize = socketBufferSize;
socket.ReceiveBufferSize = socketBufferSize;
return socket;
}
catch (Exception)
{
socket.Dispose();
throw;
}
}
protected static byte SocketReadByte(Socket socket)
{
var buffer = new byte[1];
SocketRead(socket, buffer, 0, 1);
SocketRead(socket, buffer, 0, 1, Session.InfiniteTimeSpan);
return buffer[0];
}
protected static byte SocketReadByte(Socket socket, TimeSpan readTimeout)
{
var buffer = new byte[1];
SocketRead(socket, buffer, 0, 1, readTimeout);
return buffer[0];
}
@@ -52,16 +79,31 @@ namespace Renci.SshNet.Connection
/// The number of bytes read.
/// </returns>
/// <exception cref="SshConnectionException">The socket is closed.</exception>
/// <exception cref="SshOperationTimeoutException">The read has timed-out.</exception>
/// <exception cref="SocketException">The read failed.</exception>
protected static int SocketRead(Socket socket, byte[] buffer, int offset, int length)
{
var bytesRead = SocketAbstraction.Read(socket, buffer, offset, length, Session.InfiniteTimeSpan);
return SocketRead(socket, buffer, offset, length, Session.InfiniteTimeSpan);
}
/// <summary>
/// Performs a blocking read on the socket until <paramref name="length"/> bytes are received.
/// </summary>
/// <param name="socket">The <see cref="Socket"/> to read from.</param>
/// <param name="buffer">An array of type <see cref="byte"/> that is the storage location for the received data.</param>
/// <param name="offset">The position in <paramref name="buffer"/> parameter to store the received data.</param>
/// <param name="length">The number of bytes to read.</param>
/// <param name="readTimeout">The maximum time to wait until <paramref name="length"/> bytes have been received.</param>
/// <returns>
/// The number of bytes read.
/// </returns>
/// <exception cref="SshConnectionException">The socket is closed.</exception>
/// <exception cref="SshOperationTimeoutException">The read has timed-out.</exception>
/// <exception cref="SocketException">The read failed.</exception>
protected static int SocketRead(Socket socket, byte[] buffer, int offset, int length, TimeSpan readTimeout)
{
var bytesRead = SocketAbstraction.Read(socket, buffer, offset, length, readTimeout);
if (bytesRead == 0)
{
// when we're in the disconnecting state (either triggered by client or server), then the
// SshConnectionException will interrupt the message listener loop (if not already interrupted)
// and the exception itself will be ignored (in RaiseError)
throw new SshConnectionException("An established connection was aborted by the server.",
DisconnectReason.ConnectionLost);
}
@@ -4,6 +4,10 @@ namespace Renci.SshNet.Connection
{
internal class DirectConnector : ConnectorBase
{
public DirectConnector(ISocketFactory socketFactory) : base(socketFactory)
{
}
public override Socket Connect(IConnectionInfo connectionInfo)
{
return SocketConnect(connectionInfo.Host, connectionInfo.Port, connectionInfo.Timeout);
+49 -10
View File
@@ -8,18 +8,57 @@ using System.Text.RegularExpressions;
namespace Renci.SshNet.Connection
{
/// <summary>
/// Establishes a tunnel via an HTTP proxy server.
/// </summary>
/// <remarks>
/// <list type="table">
/// <listheader>
/// <term>Specification</term>
/// <description>URL</description>
/// </listheader>
/// <item>
/// <term>HTTP CONNECT method</term>
/// <description>https://tools.ietf.org/html/rfc7231#section-4.3.6</description>
/// </item>
/// <item>
/// <term>HTTP Authentication: Basic and Digest Access Authentication</term>
/// <description>https://tools.ietf.org/html/rfc2617</description>
/// </item>
/// </list>
/// </remarks>
internal class HttpConnector : ConnectorBase
{
public HttpConnector(ISocketFactory socketFactory) : base(socketFactory)
{
}
public override Socket Connect(IConnectionInfo connectionInfo)
{
var socket = SocketConnect(connectionInfo.ProxyHost, connectionInfo.ProxyPort, connectionInfo.Timeout);
try
{
HandleProxyConnect(connectionInfo, socket);
return socket;
}
catch (Exception)
{
socket.Shutdown(SocketShutdown.Both);
socket.Dispose();
throw;
}
}
private void HandleProxyConnect(IConnectionInfo connectionInfo, Socket socket)
{
var httpResponseRe = new Regex(@"HTTP/(?<version>\d[.]\d) (?<statusCode>\d{3}) (?<reasonPhrase>.+)$");
var httpHeaderRe = new Regex(@"(?<fieldName>[^\[\]()<>@,;:\""/?={} \t]+):(?<fieldValue>.+)?");
SocketAbstraction.Send(socket, SshData.Ascii.GetBytes(string.Format("CONNECT {0}:{1} HTTP/1.0\r\n", connectionInfo.Host, connectionInfo.Port)));
// Sent proxy authorization is specified
// Sent proxy authorization if specified
if (!string.IsNullOrEmpty(connectionInfo.ProxyUsername))
{
var authorization = string.Format("Proxy-Authorization: Basic {0}\r\n",
@@ -50,9 +89,9 @@ namespace Renci.SshNet.Connection
statusCode = (HttpStatusCode)int.Parse(httpStatusCode);
if (statusCode != HttpStatusCode.OK)
{
var reasonPhrase = statusMatch.Result("${reasonPhrase}");
throw new ProxyException(string.Format("HTTP: Status code {0}, \"{1}\"", httpStatusCode,
reasonPhrase));
throw new ProxyException(string.Format("HTTP: Status code {0}, \"{1}\"",
httpStatusCode,
statusMatch.Result("${reasonPhrase}")));
}
}
@@ -78,7 +117,7 @@ namespace Renci.SshNet.Connection
if (contentLength > 0)
{
var contentBody = new byte[contentLength];
SocketRead(socket, contentBody, 0, contentLength);
SocketRead(socket, contentBody, 0, contentLength, connectionInfo.Timeout);
}
break;
}
@@ -88,21 +127,19 @@ namespace Renci.SshNet.Connection
{
throw new ProxyException("HTTP response does not contain status line.");
}
return socket;
}
/// <summary>
/// Performs a blocking read on the socket until a line is read.
/// </summary>
/// <param name="socket">The <see cref="Socket"/> to read from.</param>
/// <param name="timeout">A <see cref="TimeSpan"/> that represents the time to wait until a line is read.</param>
/// <param name="readTimeout">A <see cref="TimeSpan"/> that represents the time to wait until a line is read.</param>
/// <exception cref="SshOperationTimeoutException">The read has timed-out.</exception>
/// <exception cref="SocketException">An error occurred when trying to access the socket.</exception>
/// <returns>
/// The line read from the socket, or <c>null</c> when the remote server has shutdown and all data has been received.
/// </returns>
private static string SocketReadLine(Socket socket, TimeSpan timeout)
private static string SocketReadLine(Socket socket, TimeSpan readTimeout)
{
var encoding = SshData.Ascii;
var buffer = new List<byte>();
@@ -112,10 +149,12 @@ namespace Renci.SshNet.Connection
// to be processed by subsequent invocations
do
{
var bytesRead = SocketAbstraction.Read(socket, data, 0, data.Length, timeout);
var bytesRead = SocketAbstraction.Read(socket, data, 0, data.Length, readTimeout);
if (bytesRead == 0)
{
// the remote server shut down the socket
break;
}
var b = data[0];
buffer.Add(b);
@@ -0,0 +1,9 @@
using System.Net.Sockets;
namespace Renci.SshNet.Connection
{
internal interface ISocketFactory
{
Socket Create(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType);
}
}
@@ -0,0 +1,12 @@
using System.Net.Sockets;
namespace Renci.SshNet.Connection
{
internal class SocketFactory : ISocketFactory
{
public Socket Create(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
{
return new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp) { NoDelay = true };
}
}
}
+54 -8
View File
@@ -2,26 +2,58 @@
using Renci.SshNet.Common;
using System;
using System.Net.Sockets;
using System.Text;
namespace Renci.SshNet.Connection
{
/// <summary>
/// Establishes a tunnel via a SOCKS4 proxy server.
/// </summary>
/// <remarks>
/// https://www.openssh.com/txt/socks4.protocol
/// </remarks>
internal class Socks4Connector : ConnectorBase
{
public Socks4Connector(ISocketFactory socketFactory) : base(socketFactory)
{
}
public override Socket Connect(IConnectionInfo connectionInfo)
{
var socket = SocketConnect(connectionInfo.ProxyHost, connectionInfo.ProxyPort, connectionInfo.Timeout);
try
{
HandleProxyConnect(connectionInfo, socket);
return socket;
}
catch (Exception)
{
socket.Shutdown(SocketShutdown.Both);
socket.Dispose();
throw;
}
}
/// <summary>
/// Establishes a connection to the server via a SOCKS5 proxy.
/// </summary>
/// <param name="connectionInfo">The connection information.</param>
/// <param name="socket">The <see cref="Socket"/>.</param>
private void HandleProxyConnect(IConnectionInfo connectionInfo, Socket socket)
{
var connectionRequest = CreateSocks4ConnectionRequest(connectionInfo.Host, (ushort)connectionInfo.Port, connectionInfo.ProxyUsername);
SocketAbstraction.Send(socket, connectionRequest);
// Read null byte
if (SocketReadByte(socket) != 0)
// Read reply version
if (SocketReadByte(socket, connectionInfo.Timeout) != 0x00)
{
throw new ProxyException("SOCKS4: Null is expected.");
}
// Read response code
var code = SocketReadByte(socket);
var code = SocketReadByte(socket, connectionInfo.Timeout);
switch (code)
{
@@ -37,15 +69,14 @@ namespace Renci.SshNet.Connection
throw new ProxyException("SOCKS4: Not valid response.");
}
var dummyBuffer = new byte[6]; // field 3 (2 bytes) and field 4 (4) should be ignored
SocketRead(socket, dummyBuffer, 0, 6);
return socket;
var destBuffer = new byte[6]; // destination port and IP address should be ignored
SocketRead(socket, destBuffer, 0, destBuffer.Length, connectionInfo.Timeout);
}
private static byte[] CreateSocks4ConnectionRequest(string hostname, ushort port, string username)
{
var addressBytes = GetSocks4DestinationAddress(hostname);
var proxyUserBytes = GetProxyUserBytes(username);
var connectionRequest = new byte
[
@@ -58,7 +89,7 @@ namespace Renci.SshNet.Connection
// IP address
addressBytes.Length +
// Username
username.Length +
proxyUserBytes.Length +
// Null terminator
1
];
@@ -79,6 +110,11 @@ namespace Renci.SshNet.Connection
Buffer.BlockCopy(addressBytes, 0, connectionRequest, index, addressBytes.Length);
index += addressBytes.Length;
// User name
Buffer.BlockCopy(proxyUserBytes, 0, connectionRequest, index, proxyUserBytes.Length);
index += proxyUserBytes.Length;
// Null terminator
connectionRequest[index] = 0x00;
return connectionRequest;
@@ -99,5 +135,15 @@ namespace Renci.SshNet.Connection
throw new ProxyException(string.Format("SOCKS4 only supports IPv4. No such address found for '{0}'.", hostname));
}
private static byte[] GetProxyUserBytes(string proxyUser)
{
if (proxyUser == null)
{
return Array<byte>.Empty;
}
return Encoding.ASCII.GetBytes(proxyUser);
}
}
}
+36 -5
View File
@@ -5,12 +5,43 @@ using System.Net.Sockets;
namespace Renci.SshNet.Connection
{
/// <summary>
/// Establishes a tunnel via a SOCKS5 proxy server.
/// </summary>
/// <remarks>
/// https://en.wikipedia.org/wiki/SOCKS#SOCKS5
/// </remarks>
internal class Socks5Connector : ConnectorBase
{
public Socks5Connector(ISocketFactory socketFactory) : base(socketFactory)
{
}
public override Socket Connect(IConnectionInfo connectionInfo)
{
var socket = SocketConnect(connectionInfo.ProxyHost, connectionInfo.ProxyPort, connectionInfo.Timeout);
try
{
HandleProxyConnect(connectionInfo, socket);
return socket;
}
catch (Exception)
{
socket.Shutdown(SocketShutdown.Both);
socket.Dispose();
throw;
}
}
/// <summary>
/// Establishes a connection to the server via a SOCKS5 proxy.
/// </summary>
/// <param name="connectionInfo">The connection information.</param>
/// <param name="socket">The <see cref="Socket"/>.</param>
private void HandleProxyConnect(IConnectionInfo connectionInfo, Socket socket)
{
var greeting = new byte[]
{
// SOCKS version number
@@ -26,7 +57,9 @@ namespace Renci.SshNet.Connection
var socksVersion = SocketReadByte(socket);
if (socksVersion != 0x05)
{
throw new ProxyException(string.Format("SOCKS Version '{0}' is not supported.", socksVersion));
}
var authenticationMethod = SocketReadByte(socket);
switch (authenticationMethod)
@@ -50,7 +83,7 @@ namespace Renci.SshNet.Connection
throw new ProxyException("SOCKS5: No acceptable authentication methods were offered.");
}
var connectionRequest = CreateSocks5ConnectionRequest(connectionInfo.Host, (ushort)connectionInfo.Port);
var connectionRequest = CreateSocks5ConnectionRequest(connectionInfo.Host, (ushort) connectionInfo.Port);
SocketAbstraction.Send(socket, connectionRequest);
// Read Server SOCKS5 version
@@ -111,8 +144,6 @@ namespace Renci.SshNet.Connection
// Read 2 bytes to be ignored
SocketRead(socket, port, 0, 2);
return socket;
}
/// <summary>
@@ -145,14 +176,14 @@ namespace Renci.SshNet.Connection
authenticationRequest[index++] = 0x01;
// Length of the username
authenticationRequest[index++] = (byte)username.Length;
authenticationRequest[index++] = (byte) username.Length;
// Username
SshData.Ascii.GetBytes(username, 0, username.Length, authenticationRequest, index);
index += username.Length;
// Length of the password
authenticationRequest[index++] = (byte)password.Length;
authenticationRequest[index++] = (byte) password.Length;
// Password
SshData.Ascii.GetBytes(password, 0, password.Length, authenticationRequest, index);

Some files were not shown because too many files have changed in this diff Show More