diff --git a/src/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj b/src/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj
index 6769eabf..39f66a0e 100644
--- a/src/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj
+++ b/src/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj
@@ -1183,6 +1183,9 @@
SftpClient.cs
+
+
+ ISftpClient.cs
Sftp\Flags.cs
diff --git a/src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj b/src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj
index 6892d3b6..fb59067a 100644
--- a/src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj
+++ b/src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj
@@ -1189,6 +1189,9 @@
SftpClient.cs
+
+
+ ISftpClient.cs
Sftp\Flags.cs
diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTestBase.cs b/src/Renci.SshNet.Tests/Classes/BaseClientTestBase.cs
new file mode 100644
index 00000000..2cce2e91
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/BaseClientTestBase.cs
@@ -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 _serviceFactoryMock { get; private set; }
+ internal Mock _socketFactoryMock { get; private set; }
+ internal Mock _sessionMock { get; private set; }
+
+ protected virtual void CreateMocks()
+ {
+ _serviceFactoryMock = new Mock(MockBehavior.Strict);
+ _socketFactoryMock = new Mock(MockBehavior.Strict);
+ _sessionMock = new Mock(MockBehavior.Strict);
+ }
+
+ protected virtual void SetupData()
+ {
+ }
+
+ protected virtual void SetupMocks()
+ {
+ }
+
+ protected override void Arrange()
+ {
+ CreateMocks();
+ SetupData();
+ SetupMocks();
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs
index 792ab89d..e21f516d 100644
--- a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs
+++ b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs
@@ -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 _serviceFactoryMock;
- private Mock _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(MockBehavior.Strict);
- _sessionMock = new Mock(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]
diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NegativeOne.cs b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NegativeOne.cs
index fb58e1f4..e3b10c87 100644
--- a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NegativeOne.cs
+++ b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NegativeOne.cs
@@ -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 _serviceFactoryMock;
- private Mock _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()))
+ .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(MockBehavior.Strict);
- _sessionMock = new Mock(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()))
- .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]
diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs
index a3c807bd..26a8da00 100644
--- a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs
+++ b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs
@@ -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 _serviceFactoryMock;
- private Mock _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()))
+ .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(MockBehavior.Strict);
- _sessionMock = new Mock(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()))
- .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]
diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs
index 4430b657..25d6ec7c 100644
--- a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs
+++ b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs
@@ -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 _serviceFactoryMock;
- private Mock _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()))
+ .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(MockBehavior.Strict);
- _sessionMock = new Mock(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()))
- .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
diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_Connect.cs b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_Connect.cs
new file mode 100644
index 00000000..51cd2d81
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_Connect.cs
@@ -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 _socketFactory2Mock;
+ private Mock _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(MockBehavior.Strict);
+ _session2Mock = new Mock(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)
+ {
+ }
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_KeepAliveInterval_NotNegativeOne.cs b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_KeepAliveInterval_NotNegativeOne.cs
index 588bfd83..1ca4b19d 100644
--- a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_KeepAliveInterval_NotNegativeOne.cs
+++ b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_KeepAliveInterval_NotNegativeOne.cs
@@ -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 _serviceFactoryMock;
- private Mock _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()))
+ .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(MockBehavior.Strict);
- _sessionMock = new Mock(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()))
- .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]
diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_NotConnected_KeepAliveInterval_NotNegativeOne.cs b/src/Renci.SshNet.Tests/Classes/BaseClientTest_NotConnected_KeepAliveInterval_NotNegativeOne.cs
index dfaa8b27..0f449c82 100644
--- a/src/Renci.SshNet.Tests/Classes/BaseClientTest_NotConnected_KeepAliveInterval_NotNegativeOne.cs
+++ b/src/Renci.SshNet.Tests/Classes/BaseClientTest_NotConnected_KeepAliveInterval_NotNegativeOne.cs
@@ -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 _serviceFactoryMock;
- private Mock _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(MockBehavior.Strict);
- _sessionMock = new Mock(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()))
.Returns(true)
diff --git a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedBySuccessInAlternateBranch.cs b/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedBySuccessInAlternateBranch.cs
index d60549e5..16f08ba9 100644
--- a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedBySuccessInAlternateBranch.cs
+++ b/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedBySuccessInAlternateBranch.cs
@@ -181,4 +181,4 @@ namespace Renci.SshNet.Tests.Classes
PublicKeyAuthenticationMethodMock.Verify(p => p.Authenticate(SessionMock.Object), Times.Exactly(2));
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Common/BigIntegerTest.cs b/src/Renci.SshNet.Tests/Classes/Common/BigIntegerTest.cs
index 8cca838d..c99fb2a6 100644
--- a/src/Renci.SshNet.Tests/Classes/Common/BigIntegerTest.cs
+++ b/src/Renci.SshNet.Tests/Classes/Common/BigIntegerTest.cs
@@ -1506,10 +1506,12 @@ namespace Renci.SshNet.Tests.Classes.Common
Assert.AreEqual("0", a.ToString(), "#4");
a = new BigInteger();
+#pragma warning disable CS1718 // Comparison made to same variable
Assert.AreEqual(true, a == a, "#5");
a = new BigInteger();
Assert.AreEqual(false, a < a, "#6");
+#pragma warning restore CS1718 // Comparison made to same variable
a = new BigInteger();
Assert.AreEqual(true, a < 10L, "#7");
diff --git a/src/Renci.SshNet.Tests/Classes/Common/PacketDumpTest.cs b/src/Renci.SshNet.Tests/Classes/Common/PacketDumpTest.cs
new file mode 100644
index 00000000..00401915
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Common/PacketDumpTest.cs
@@ -0,0 +1,155 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
+using System;
+
+namespace Renci.SshNet.Tests.Classes.Common
+{
+ [TestClass]
+ public class PacketDumpTest
+ {
+ [TestMethod]
+ public void Create_ByteArrayAndIndentLevel_DataIsNull()
+ {
+ const byte[] data = null;
+
+ try
+ {
+ PacketDump.Create(data, 0);
+ Assert.Fail();
+ }
+ catch (ArgumentNullException ex)
+ {
+ Assert.IsNull(ex.InnerException);
+ Assert.AreEqual("data", ex.ParamName);
+ }
+ }
+
+ [TestMethod]
+ public void Create_ByteArrayAndIndentLevel_IndentLevelLessThanZero()
+ {
+ var data = new byte[0];
+
+ try
+ {
+ PacketDump.Create(data, -1);
+ Assert.Fail();
+ }
+ catch (ArgumentOutOfRangeException ex)
+ {
+ Assert.IsNull(ex.InnerException);
+ Assert.AreEqual(string.Format("Cannot be less than zero.{0}Parameter name: {1}", Environment.NewLine, ex.ParamName), ex.Message);
+ Assert.AreEqual("indentLevel", ex.ParamName);
+ }
+ }
+
+ [TestMethod]
+ public void Create_ByteArrayAndIndentLevel_DataIsEmpty()
+ {
+ var data = new byte[0];
+
+ var actual = PacketDump.Create(data, 2);
+
+ Assert.AreEqual(string.Empty, actual);
+ }
+
+ [TestMethod]
+ public void Create_ByteArrayAndIndentLevel_DataIsMultipleOfLineWidth_IndentLevelTwo()
+ {
+ var data = new byte[]
+ {
+ 0x07, 0x00, 0x1f, 0x65, 0x20, 0x62, 0x09, 0x44, 0x7f, 0x0d, 0x0a, 0x36, 0x80, 0x53, 0x53, 0x48,
+ 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x32, 0x30, 0x32, 0x30, 0x20, 0xf6, 0x7a, 0x32, 0x7f, 0x1f, 0x7e
+ };
+ var expected = " 00000000 07 00 1F 65 20 62 09 44 7F 0D 0A 36 80 53 53 48 ...e b.D...6.SSH" +
+ Environment.NewLine +
+ " 00000010 2E 4E 45 54 20 32 30 32 30 20 F6 7A 32 7F 1F 7E .NET 2020 .z2..~";
+
+ var actual = PacketDump.Create(data, 2);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [TestMethod]
+ public void Create_ByteArrayAndIndentLevel_DataIsMultipleOfLineWidth_IndentLevelZero()
+ {
+ var data = new byte[]
+ {
+ 0x07, 0x00, 0x1f, 0x65, 0x20, 0x62, 0x09, 0x44, 0x7f, 0x0d, 0x0a, 0x36, 0x80, 0x53, 0x53, 0x48,
+ 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x32, 0x30, 0x32, 0x30, 0x20, 0xf6, 0x7a, 0x32, 0x7f, 0x1f, 0x7e
+ };
+ var expected = "00000000 07 00 1F 65 20 62 09 44 7F 0D 0A 36 80 53 53 48 ...e b.D...6.SSH" +
+ Environment.NewLine +
+ "00000010 2E 4E 45 54 20 32 30 32 30 20 F6 7A 32 7F 1F 7E .NET 2020 .z2..~";
+
+ var actual = PacketDump.Create(data, 0);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [TestMethod]
+ public void Create_ByteArrayAndIndentLevel_DataIsLineWith()
+ {
+ var data = new byte[]
+ {
+ 0x07, 0x00, 0x1f, 0x65, 0x20, 0x62, 0x09, 0x44, 0x7f, 0x0d, 0x0a, 0x36, 0x80, 0x53, 0x53, 0x48
+ };
+ var expected = " 00000000 07 00 1F 65 20 62 09 44 7F 0D 0A 36 80 53 53 48 ...e b.D...6.SSH";
+
+ var actual = PacketDump.Create(data, 2);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [TestMethod]
+ public void Create_ByteArrayAndIndentLevel_DataIsLessThanLineWith()
+ {
+ var data = new byte[]
+ {
+ 0x07, 0x00, 0x1f, 0x65, 0x20, 0x62, 0x09, 0x44, 0x7f, 0x0d, 0x0a, 0x36, 0x80, 0x53
+ };
+ var expected = " 00000000 07 00 1F 65 20 62 09 44 7F 0D 0A 36 80 53 ...e b.D...6.S";
+
+ var actual = PacketDump.Create(data, 2);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [TestMethod]
+ public void Create_ByteArrayAndIndentLevel_DataIsGreaterThanLineWidthButLessThanMultipleOfLineWidth()
+ {
+ var data = new byte[]
+ {
+ 0x07, 0x00, 0x1f, 0x65, 0x20, 0x62, 0x09, 0x44, 0x7f, 0x0d, 0x0a, 0x36, 0x80, 0x53, 0x53, 0x48,
+ 0x2e, 0x4e, 0x45, 0x54
+ };
+ var expected = " 00000000 07 00 1F 65 20 62 09 44 7F 0D 0A 36 80 53 53 48 ...e b.D...6.SSH" +
+ Environment.NewLine +
+ " 00000010 2E 4E 45 54 .NET";
+
+ var actual = PacketDump.Create(data, 2);
+
+ Assert.AreEqual(expected, actual);
+ }
+
+ [TestMethod]
+ public void Create_ByteArrayAndIndentLevel_DataIsGreaterThanMultipleOfLineWidth()
+ {
+ var data = new byte[]
+ {
+ 0x07, 0x00, 0x1f, 0x65, 0x20, 0x62, 0x09, 0x44, 0x7f, 0x0d, 0x0a, 0x36, 0x80, 0x53, 0x53, 0x48,
+ 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x32, 0x30, 0x32, 0x30, 0x20, 0xf6, 0x7a, 0x32, 0x7f, 0x1f, 0x7e,
+ 0x78, 0x54, 0x00, 0x52
+ };
+ var expected = " 00000000 07 00 1F 65 20 62 09 44 7F 0D 0A 36 80 53 53 48 ...e b.D...6.SSH" +
+ Environment.NewLine +
+ " 00000010 2E 4E 45 54 20 32 30 32 30 20 F6 7A 32 7F 1F 7E .NET 2020 .z2..~" +
+ Environment.NewLine +
+ " 00000020 78 54 00 52 xT.R";
+
+ var actual = PacketDump.Create(data, 2);
+
+ Assert.AreEqual(expected, actual);
+
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingRead.cs b/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingRead.cs
index 7438ceda..fb010c14 100644
--- a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingRead.cs
+++ b/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingRead.cs
@@ -1,18 +1,18 @@
-using System;
+using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Renci.SshNet.Common;
+using Renci.SshNet.Tests.Common;
namespace Renci.SshNet.Tests.Classes.Common
{
[TestClass]
- public class PipeStream_Close_BlockingRead
+ public class PipeStream_Close_BlockingRead : TripleATestBase
{
private PipeStream _pipeStream;
private int _bytesRead;
- private IAsyncResult _asyncReadResult;
+ private Thread _readThread;
- [TestInitialize]
- public void Init()
+ protected override void Arrange()
{
_pipeStream = new PipeStream();
@@ -22,26 +22,25 @@ namespace Renci.SshNet.Tests.Classes.Common
_bytesRead = 123;
- Action readAction = () => _bytesRead = _pipeStream.Read(new byte[4], 0, 4);
- _asyncReadResult = readAction.BeginInvoke(null, null);
- // ensure we've started reading
- _asyncReadResult.AsyncWaitHandle.WaitOne(50);
+ _readThread = new Thread(() => _bytesRead = _pipeStream.Read(new byte[4], 0, 4));
+ _readThread.Start();
- Act();
+ // ensure we've started reading
+ Assert.IsFalse(_readThread.Join(50));
}
- protected void Act()
+ protected override void Act()
{
_pipeStream.Close();
// give async read time to complete
- _asyncReadResult.AsyncWaitHandle.WaitOne(100);
+ _readThread.Join(100);
}
[TestMethod]
public void BlockingReadShouldHaveBeenInterrupted()
{
- Assert.IsTrue(_asyncReadResult.IsCompleted);
+ Assert.AreEqual(ThreadState.Stopped, _readThread.ThreadState);
}
[TestMethod]
diff --git a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingWrite.cs b/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingWrite.cs
index d270679a..1fbd2d15 100644
--- a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingWrite.cs
+++ b/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingWrite.cs
@@ -1,22 +1,23 @@
using System;
+using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Renci.SshNet.Common;
+using Renci.SshNet.Tests.Common;
namespace Renci.SshNet.Tests.Classes.Common
{
[TestClass]
- public class PipeStream_Close_BlockingWrite
+ public class PipeStream_Close_BlockingWrite : TripleATestBase
{
private PipeStream _pipeStream;
private Exception _writeException;
- private IAsyncResult _asyncWriteResult;
+ private Thread _writehread;
- [TestInitialize]
- public void Init()
+ protected override void Arrange()
{
_pipeStream = new PipeStream {MaxBufferLength = 3};
- Action writeAction = () =>
+ _writehread = new Thread(() =>
{
_pipeStream.WriteByte(10);
_pipeStream.WriteByte(13);
@@ -33,26 +34,25 @@ namespace Renci.SshNet.Tests.Classes.Common
_writeException = ex;
throw;
}
- };
- _asyncWriteResult = writeAction.BeginInvoke(null, null);
- // ensure we've started writing
- _asyncWriteResult.AsyncWaitHandle.WaitOne(50);
+ });
+ _writehread.Start();
- Act();
+ // ensure we've started writing
+ Assert.IsFalse(_writehread.Join(50));
}
- protected void Act()
+ protected override void Act()
{
_pipeStream.Close();
- // give async write time to complete
- _asyncWriteResult.AsyncWaitHandle.WaitOne(100);
+ // give write time to complete
+ _writehread.Join(100);
}
[TestMethod]
public void BlockingWriteShouldHaveBeenInterrupted()
{
- Assert.IsTrue(_asyncWriteResult.IsCompleted);
+ Assert.AreEqual(ThreadState.Stopped, _writehread.ThreadState);
}
[TestMethod]
diff --git a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_BytesRemainingAfterRead.cs b/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_BytesRemainingAfterRead.cs
index b16c908e..3af0a3de 100644
--- a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_BytesRemainingAfterRead.cs
+++ b/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_BytesRemainingAfterRead.cs
@@ -1,20 +1,19 @@
-using System;
-using System.Threading;
+using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Renci.SshNet.Common;
+using Renci.SshNet.Tests.Common;
namespace Renci.SshNet.Tests.Classes.Common
{
[TestClass]
- public class PipeStream_Flush_BytesRemainingAfterRead
+ public class PipeStream_Flush_BytesRemainingAfterRead : TripleATestBase
{
private PipeStream _pipeStream;
private byte[] _readBuffer;
private int _bytesRead;
- private IAsyncResult _asyncReadResult;
+ private Thread _readThread;
- [TestInitialize]
- public void Init()
+ protected override void Arrange()
{
_pipeStream = new PipeStream();
_pipeStream.WriteByte(10);
@@ -27,25 +26,25 @@ namespace Renci.SshNet.Tests.Classes.Common
_bytesRead = 0;
_readBuffer = new byte[4];
- Action readAction = () => _bytesRead = _pipeStream.Read(_readBuffer, 0, _readBuffer.Length);
- _asyncReadResult = readAction.BeginInvoke(null, null);
- _asyncReadResult.AsyncWaitHandle.WaitOne(50);
+ _readThread = new Thread(() => _bytesRead = _pipeStream.Read(_readBuffer, 0, _readBuffer.Length));
+ _readThread.Start();
- Act();
+ // ensure we've started reading
+ _readThread.Join(50);
}
- protected void Act()
+ protected override void Act()
{
_pipeStream.Flush();
// give async read time to complete
- _asyncReadResult.AsyncWaitHandle.WaitOne(100);
+ _readThread.Join(100);
}
[TestMethod]
public void AsyncReadShouldHaveFinished()
{
- Assert.IsTrue(_asyncReadResult.IsCompleted);
+ Assert.AreEqual(ThreadState.Stopped, _readThread.ThreadState);
}
[TestMethod]
diff --git a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_NoBytesRemainingAfterRead.cs b/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_NoBytesRemainingAfterRead.cs
index eac2f20b..44c7f3f7 100644
--- a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_NoBytesRemainingAfterRead.cs
+++ b/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_NoBytesRemainingAfterRead.cs
@@ -1,19 +1,19 @@
-using System;
+using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Renci.SshNet.Common;
+using Renci.SshNet.Tests.Common;
namespace Renci.SshNet.Tests.Classes.Common
{
[TestClass]
- public class PipeStream_Flush_NoBytesRemainingAfterRead
+ public class PipeStream_Flush_NoBytesRemainingAfterRead : TripleATestBase
{
private PipeStream _pipeStream;
private byte[] _readBuffer;
private int _bytesRead;
- private IAsyncResult _asyncReadResult;
+ private Thread _readThread;
- [TestInitialize]
- public void Init()
+ protected override void Arrange()
{
_pipeStream = new PipeStream();
_pipeStream.WriteByte(10);
@@ -22,25 +22,25 @@ namespace Renci.SshNet.Tests.Classes.Common
_bytesRead = 0;
_readBuffer = new byte[4];
- Action readAction = () => _bytesRead = _pipeStream.Read(_readBuffer, 0, _readBuffer.Length);
- _asyncReadResult = readAction.BeginInvoke(null, null);
- _asyncReadResult.AsyncWaitHandle.WaitOne(50);
+ _readThread = new Thread(() => _bytesRead = _pipeStream.Read(_readBuffer, 0, _readBuffer.Length));
+ _readThread.Start();
- Act();
+ // ensure we've started reading
+ Assert.IsFalse(_readThread.Join(50));
}
- protected void Act()
+ protected override void Act()
{
_pipeStream.Flush();
// give async read time to complete
- _asyncReadResult.AsyncWaitHandle.WaitOne(100);
+ _readThread.Join(100);
}
[TestMethod]
public void AsyncReadShouldHaveFinished()
{
- Assert.IsTrue(_asyncReadResult.IsCompleted);
+ Assert.AreEqual(ThreadState.Stopped, _readThread.ThreadState);
}
[TestMethod]
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTestBase.cs b/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTestBase.cs
new file mode 100644
index 00000000..edb14680
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTestBase.cs
@@ -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 SocketFactoryMock { get; private set; }
+ internal DirectConnector Connector { get; private set; }
+ internal SocketFactory SocketFactory { get; private set; }
+
+ protected virtual void CreateMocks()
+ {
+ SocketFactoryMock = new Mock(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"));
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_ConnectionRefusedByServer.cs b/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_ConnectionRefusedByServer.cs
new file mode 100644
index 00000000..40fd93b5
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_ConnectionRefusedByServer.cs
@@ -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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_ConnectionSucceeded.cs b/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_ConnectionSucceeded.cs
new file mode 100644
index 00000000..5741c186
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_ConnectionSucceeded.cs
@@ -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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_HostNameInvalid.cs b/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_HostNameInvalid.cs
new file mode 100644
index 00000000..05a69e94
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_HostNameInvalid.cs
@@ -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);
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_TimeoutConnectingToServer.cs b/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_TimeoutConnectingToServer.cs
new file mode 100644
index 00000000..b8e4246a
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_TimeoutConnectingToServer.cs
@@ -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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTestBase.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTestBase.cs
new file mode 100644
index 00000000..82cfe0c2
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTestBase.cs
@@ -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 SocketFactoryMock { get; private set; }
+ internal HttpConnector Connector { get; private set; }
+ internal SocketFactory SocketFactory { get; private set; }
+
+ protected virtual void CreateMocks()
+ {
+ SocketFactoryMock = new Mock(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();
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ConnectionToProxyRefused.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ConnectionToProxyRefused.cs
new file mode 100644
index 00000000..5c790b4c
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ConnectionToProxyRefused.cs
@@ -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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyClosesConnectionBeforeStatusLineIsSent.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyClosesConnectionBeforeStatusLineIsSent.cs
new file mode 100644
index 00000000..72bdca90
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyClosesConnectionBeforeStatusLineIsSent.cs
@@ -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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyHostInvalid.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyHostInvalid.cs
new file mode 100644
index 00000000..5843947d
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyHostInvalid.cs
@@ -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);
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsEmpty.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsEmpty.cs
new file mode 100644
index 00000000..c94933b2
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsEmpty.cs
@@ -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 _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();
+ _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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsNull.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsNull.cs
new file mode 100644
index 00000000..277a6f29
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsNull.cs
@@ -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 _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();
+ _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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseDoesNotContainHttpStatusLine.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseDoesNotContainHttpStatusLine.cs
new file mode 100644
index 00000000..b9f90019
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseDoesNotContainHttpStatusLine.cs
@@ -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 _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();
+ _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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_ExtraTextBeforeStatusLine.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_ExtraTextBeforeStatusLine.cs
new file mode 100644
index 00000000..70491330
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_ExtraTextBeforeStatusLine.cs
@@ -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 _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();
+ _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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_HeadersAndContent.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_HeadersAndContent.cs
new file mode 100644
index 00000000..dc0bba59
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_HeadersAndContent.cs
@@ -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 _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();
+ _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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_OnlyHeaders.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_OnlyHeaders.cs
new file mode 100644
index 00000000..235b4dc0
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_OnlyHeaders.cs
@@ -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 _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();
+ _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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIsNot200.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIsNot200.cs
new file mode 100644
index 00000000..9eb0094b
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIsNot200.cs
@@ -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 _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();
+ _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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsEmpty.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsEmpty.cs
new file mode 100644
index 00000000..33c22253
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsEmpty.cs
@@ -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_ProxyUserNameIsEmpty : HttpConnectorTestBase
+ {
+ private ConnectionInfo _connectionInfo;
+ private AsyncSocketListener _proxyServer;
+ private bool _disconnected;
+ private Socket _clientSocket;
+ private List _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();
+ _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 (_proxyServer != null)
+ {
+ _proxyServer.Dispose();
+ }
+
+ if (_clientSocket != null)
+ {
+ _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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNotNullAndNotEmpty.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNotNullAndNotEmpty.cs
new file mode 100644
index 00000000..dad0e74b
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNotNullAndNotEmpty.cs
@@ -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 _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();
+ _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());
+ }
+ }
+}
+
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNull.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNull.cs
new file mode 100644
index 00000000..3de1bddb
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNull.cs
@@ -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 _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();
+ _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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutConnectingToProxy.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutConnectingToProxy.cs
new file mode 100644
index 00000000..1a65fec1
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutConnectingToProxy.cs
@@ -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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingHttpContent.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingHttpContent.cs
new file mode 100644
index 00000000..29ea435d
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingHttpContent.cs
@@ -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 _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();
+ _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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingStatusLine.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingStatusLine.cs
new file mode 100644
index 00000000..254262ba
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingStatusLine.cs
@@ -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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ConnectionClosedByServer_NoDataSentByServer.cs b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ConnectionClosedByServer_NoDataSentByServer.cs
new file mode 100644
index 00000000..c01aacc1
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ConnectionClosedByServer_NoDataSentByServer.cs
@@ -0,0 +1,122 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
+using Renci.SshNet.Connection;
+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 ProtocolVersionExchangeTest_ConnectionClosedByServer_NoDataSentByServer
+ {
+ private AsyncSocketListener _server;
+ private ProtocolVersionExchange _protocolVersionExchange;
+ private string _clientVersion;
+ private TimeSpan _timeout;
+ private IPEndPoint _serverEndPoint;
+ private List _dataReceivedByServer;
+ private bool _clientDisconnected;
+ private Socket _client;
+ private SshConnectionException _actualException;
+
+ [TestInitialize]
+ public void Setup()
+ {
+ Arrange();
+ Act();
+ }
+
+ [TestCleanup]
+ public void Cleanup()
+ {
+ if (_server != null)
+ {
+ _server.Dispose();
+ _server = null;
+ }
+
+ if (_client != null)
+ {
+ _client.Shutdown(SocketShutdown.Both);
+ _client.Close();
+ _client = null;
+ }
+ }
+
+ protected void Arrange()
+ {
+ _clientVersion = "\uD55C";
+ _timeout = TimeSpan.FromSeconds(5);
+ _serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
+ _dataReceivedByServer = new List();
+
+ _server = new AsyncSocketListener(_serverEndPoint);
+ _server.Start();
+ _server.BytesReceived += (bytes, socket) =>
+ {
+ _dataReceivedByServer.AddRange(bytes);
+ socket.Shutdown(SocketShutdown.Send);
+ };
+ _server.Disconnected += (socket) => _clientDisconnected = true;
+
+ _client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ _client.Connect(_serverEndPoint);
+
+ _protocolVersionExchange = new ProtocolVersionExchange();
+ }
+
+ protected void Act()
+ {
+ try
+ {
+ _protocolVersionExchange.Start(_clientVersion, _client, _timeout);
+ Assert.Fail();
+ }
+ catch (SshConnectionException ex)
+ {
+ _actualException = ex;
+ }
+ }
+
+ [TestMethod]
+ public void StartShouldHaveThrownSshConnectionException()
+ {
+ Assert.IsNotNull(_actualException);
+ Assert.IsNull(_actualException.InnerException);
+ Assert.AreEqual(string.Format("The server response does not contain an SSH identification string.{0}" +
+ "The connection to the remote server was closed before any data was received.{0}{0}" +
+ "More information on the Protocol Version Exchange is available here:{0}" +
+ "https://tools.ietf.org/html/rfc4253#section-4.2",
+ Environment.NewLine),
+ _actualException.Message);
+ }
+
+ [TestMethod]
+ public void ClientIdentificationWasSentToServer()
+ {
+ Assert.AreEqual(5, _dataReceivedByServer.Count);
+
+ Assert.AreEqual(0xed, _dataReceivedByServer[0]);
+ Assert.AreEqual(0x95, _dataReceivedByServer[1]);
+ Assert.AreEqual(0x9c, _dataReceivedByServer[2]);
+ Assert.AreEqual(0x0d, _dataReceivedByServer[3]);
+ Assert.AreEqual(0x0a, _dataReceivedByServer[4]);
+ }
+
+ [TestMethod]
+ public void ConnectionIsClosedByServer()
+ {
+ Assert.IsTrue(_client.Connected);
+ Assert.IsFalse(_clientDisconnected);
+
+ var bytesReceived = _client.Receive(new byte[1]);
+ Assert.AreEqual(0, bytesReceived);
+
+ Assert.IsTrue(_client.Connected);
+ Assert.IsFalse(_clientDisconnected);
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseContainsNullCharacter.cs b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseContainsNullCharacter.cs
new file mode 100644
index 00000000..29792888
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseContainsNullCharacter.cs
@@ -0,0 +1,132 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+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;
+using System.Text;
+
+namespace Renci.SshNet.Tests.Classes.Connection
+{
+ [TestClass]
+ public class ProtocolVersionExchangeTest_ServerResponseContainsNullCharacter
+ {
+ private AsyncSocketListener _server;
+ private ProtocolVersionExchange _protocolVersionExchange;
+ private string _clientVersion;
+ private TimeSpan _timeout;
+ private IPEndPoint _serverEndPoint;
+ private List _dataReceivedByServer;
+ private byte[] _serverIdentification;
+ private bool _clientDisconnected;
+ private Socket _client;
+ private SshConnectionException _actualException;
+
+ [TestInitialize]
+ public void Setup()
+ {
+ Arrange();
+ Act();
+ }
+
+ [TestCleanup]
+ public void Cleanup()
+ {
+ if (_server != null)
+ {
+ _server.Dispose();
+ _server = null;
+ }
+
+ if (_client != null)
+ {
+ _client.Shutdown(SocketShutdown.Both);
+ _client.Close();
+ _client = null;
+ }
+ }
+
+ protected void Arrange()
+ {
+ _clientVersion = "SSH-2.0-Renci.SshNet.SshClient.0.0.1";
+ _timeout = TimeSpan.FromSeconds(5);
+ _serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
+ _dataReceivedByServer = new List();
+ _serverIdentification = Encoding.UTF8.GetBytes("\uD55C!\0\uD55CSSH -2.0-Renci.SshNet.SshClient.0.0.1");
+
+ _server = new AsyncSocketListener(_serverEndPoint);
+ _server.Start();
+ _server.Connected += socket => socket.Send(_serverIdentification);
+ _server.BytesReceived += (bytes, socket) =>
+ {
+ _dataReceivedByServer.AddRange(bytes);
+ };
+ _server.Disconnected += (socket) => _clientDisconnected = true;
+
+ _client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ _client.Connect(_serverEndPoint);
+
+ _protocolVersionExchange = new ProtocolVersionExchange();
+ }
+
+ protected void Act()
+ {
+ try
+ {
+ _protocolVersionExchange.Start(_clientVersion, _client, _timeout);
+ Assert.Fail();
+ }
+ catch (SshConnectionException ex)
+ {
+ _actualException = ex;
+ }
+ }
+
+ [TestMethod]
+ public void StartShouldHaveThrownSshConnectionException()
+ {
+ var expectedMessage = string.Format("The server response contains a null character at position 0x00000005:{0}{0}" +
+ " 00000000 ED 95 9C 21 00 ...!.{0}{0}" +
+ "A server must not send a null character before the Protocol Version Exchange is complete.{0}{0}" +
+ "More information is available here:{0}" +
+ "https://tools.ietf.org/html/rfc4253#section-4.2",
+ Environment.NewLine);
+
+ Assert.IsNotNull(_actualException);
+ Assert.IsNull(_actualException.InnerException);
+ Assert.AreEqual(expectedMessage, _actualException.Message);
+ }
+
+ [TestMethod]
+ public void ClientIdentificationWasSentToServer()
+ {
+ var expected = Encoding.UTF8.GetBytes(_clientVersion);
+
+ Assert.AreEqual(expected.Length + 2, _dataReceivedByServer.Count);
+
+ Assert.IsTrue(expected.SequenceEqual(_dataReceivedByServer.Take(expected.Length)));
+ Assert.AreEqual(Session.CarriageReturn, _dataReceivedByServer[_dataReceivedByServer.Count - 2]);
+ Assert.AreEqual(Session.LineFeed, _dataReceivedByServer[_dataReceivedByServer.Count - 1]);
+ }
+
+ [TestMethod]
+ public void ClientRemainsConnected()
+ {
+ Assert.IsTrue(_client.Connected);
+ Assert.IsFalse(_clientDisconnected);
+ }
+
+ [TestMethod]
+ public void ClientHasNotReadPastNullCharacter()
+ {
+ var buffer = new byte[1];
+
+ var bytesReceived = _client.Receive(buffer);
+ Assert.AreEqual(1, bytesReceived);
+ Assert.AreEqual(0xed, buffer[0]);
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseInvalid_SshIdentificationOnlyContainsProtocolVersion.cs b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseInvalid_SshIdentificationOnlyContainsProtocolVersion.cs
new file mode 100644
index 00000000..ff2bc5e5
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseInvalid_SshIdentificationOnlyContainsProtocolVersion.cs
@@ -0,0 +1,128 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+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;
+using System.Text;
+
+namespace Renci.SshNet.Tests.Classes.Connection
+{
+ [TestClass]
+ public class ProtocolVersionExchangeTest_ServerResponseInvalid_SshIdentificationOnlyContainsProtocolVersion
+ {
+ private AsyncSocketListener _server;
+ private ProtocolVersionExchange _protocolVersionExchange;
+ private string _clientVersion;
+ private TimeSpan _timeout;
+ private IPEndPoint _serverEndPoint;
+ private List _dataReceivedByServer;
+ private byte[] _serverIdentification;
+ private bool _clientDisconnected;
+ private Socket _client;
+ private SshConnectionException _actualException;
+
+ [TestInitialize]
+ public void Setup()
+ {
+ Arrange();
+ Act();
+ }
+
+ [TestCleanup]
+ public void Cleanup()
+ {
+ if (_server != null)
+ {
+ _server.Dispose();
+ _server = null;
+ }
+
+ if (_client != null)
+ {
+ _client.Shutdown(SocketShutdown.Both);
+ _client.Close();
+ _client = null;
+ }
+ }
+
+ protected void Arrange()
+ {
+ _clientVersion = "SSH-2.0-Renci.SshNet.SshClient.0.0.1";
+ _timeout = TimeSpan.FromSeconds(5);
+ _serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
+ _dataReceivedByServer = new List();
+ _serverIdentification = Encoding.UTF8.GetBytes("SSH-2.0\r\n");
+
+ _server = new AsyncSocketListener(_serverEndPoint);
+ _server.Start();
+ _server.BytesReceived += (bytes, socket) =>
+ {
+ _dataReceivedByServer.AddRange(bytes);
+ socket.Send(_serverIdentification);
+ socket.Shutdown(SocketShutdown.Send);
+ };
+ _server.Disconnected += (socket) => _clientDisconnected = true;
+
+ _client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ _client.Connect(_serverEndPoint);
+
+ _protocolVersionExchange = new ProtocolVersionExchange();
+ }
+
+ protected void Act()
+ {
+ try
+ {
+ _protocolVersionExchange.Start(_clientVersion, _client, _timeout);
+ Assert.Fail();
+ }
+ catch (SshConnectionException ex)
+ {
+ _actualException = ex;
+ }
+ }
+
+ [TestMethod]
+ public void StartShouldHaveThrownSshConnectionException()
+ {
+ var expectedMessage = string.Format("The server response does not contain an SSH identification string:{0}{0}" +
+ " 00000000 53 53 48 2D 32 2E 30 0D 0A SSH-2.0..{0}{0}" +
+ "More information on the Protocol Version Exchange is available here:{0}" +
+ "https://tools.ietf.org/html/rfc4253#section-4.2",
+ Environment.NewLine);
+
+ Assert.IsNotNull(_actualException);
+ Assert.IsNull(_actualException.InnerException);
+ Assert.AreEqual(expectedMessage, _actualException.Message);
+ }
+
+ [TestMethod]
+ public void ClientIdentificationWasSentToServer()
+ {
+ var expected = Encoding.UTF8.GetBytes(_clientVersion);
+
+ Assert.AreEqual(expected.Length + 2, _dataReceivedByServer.Count);
+
+ Assert.IsTrue(expected.SequenceEqual(_dataReceivedByServer.Take(expected.Length)));
+ Assert.AreEqual(Session.CarriageReturn, _dataReceivedByServer[_dataReceivedByServer.Count - 2]);
+ Assert.AreEqual(Session.LineFeed, _dataReceivedByServer[_dataReceivedByServer.Count - 1]);
+ }
+
+ [TestMethod]
+ public void ConnectionIsClosedByServer()
+ {
+ Assert.IsTrue(_client.Connected);
+ Assert.IsFalse(_clientDisconnected);
+
+ var bytesReceived = _client.Receive(new byte[1]);
+ Assert.AreEqual(0, bytesReceived);
+
+ Assert.IsTrue(_client.Connected);
+ Assert.IsFalse(_clientDisconnected);
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_Comments.cs b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_Comments.cs
new file mode 100644
index 00000000..df533ebe
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_Comments.cs
@@ -0,0 +1,119 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+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;
+using System.Text;
+
+namespace Renci.SshNet.Tests.Classes.Connection
+{
+ [TestClass]
+ public class ProtocolVersionExchangeTest_ServerResponseValid_Comments
+ {
+ private AsyncSocketListener _server;
+ private ProtocolVersionExchange _protocolVersionExchange;
+ private string _clientVersion;
+ private TimeSpan _timeout;
+ private IPEndPoint _serverEndPoint;
+ private List _dataReceivedByServer;
+ private byte[] _serverIdentification;
+ private bool _clientDisconnected;
+ private Socket _client;
+ private SshIdentification _actual;
+
+ [TestInitialize]
+ public void Setup()
+ {
+ Arrange();
+ Act();
+ }
+
+ [TestCleanup]
+ public void Cleanup()
+ {
+ if (_server != null)
+ {
+ _server.Dispose();
+ _server = null;
+ }
+
+ if (_client != null)
+ {
+ _client.Shutdown(SocketShutdown.Both);
+ _client.Close();
+ _client = null;
+ }
+ }
+
+ protected void Arrange()
+ {
+ _clientVersion = "SSH-2.0-Renci.SshNet.SshClient.0.0.1";
+ _timeout = TimeSpan.FromSeconds(5);
+ _serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
+ _dataReceivedByServer = new List();
+ _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.Send);
+ };
+ _server.Disconnected += (socket) => _clientDisconnected = true;
+
+ _client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ _client.Connect(_serverEndPoint);
+
+ _protocolVersionExchange = new ProtocolVersionExchange();
+ }
+
+ protected void Act()
+ {
+ _actual = _protocolVersionExchange.Start(_clientVersion, _client, _timeout);
+ }
+
+ [TestMethod]
+ public void StartShouldReturnIdentificationOfServer()
+ {
+ Assert.IsNotNull(_actual);
+ Assert.AreEqual("ABC2.0", _actual.ProtocolVersion);
+ Assert.AreEqual("OurSSHAppliance-1.4.7", _actual.SoftwareVersion);
+ Assert.AreEqual("Use at own risk.\uD55C", _actual.Comments);
+ }
+
+ [TestMethod]
+ public void ClientIdentificationWasSentToServer()
+ {
+ var expected = Encoding.UTF8.GetBytes(_clientVersion);
+
+ Assert.AreEqual(expected.Length + 2, _dataReceivedByServer.Count);
+
+ Assert.IsTrue(expected.SequenceEqual(_dataReceivedByServer.Take(expected.Length)));
+ Assert.AreEqual(Session.CarriageReturn, _dataReceivedByServer[_dataReceivedByServer.Count - 2]);
+ Assert.AreEqual(Session.LineFeed, _dataReceivedByServer[_dataReceivedByServer.Count - 1]);
+ }
+
+ [TestMethod]
+ public void ClientRemainsConnected()
+ {
+ Assert.IsTrue(_client.Connected);
+ Assert.IsFalse(_clientDisconnected);
+ }
+
+ [TestMethod]
+ public void ClientDidNotReadPastIdentification()
+ {
+ var buffer = new byte[1];
+
+ var bytesReceived = _client.Receive(buffer);
+ Assert.AreEqual(1, bytesReceived);
+ Assert.AreEqual(0x21, buffer[0]);
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_NoComments.cs b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_NoComments.cs
new file mode 100644
index 00000000..8b4f5997
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_NoComments.cs
@@ -0,0 +1,119 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+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;
+using System.Text;
+
+namespace Renci.SshNet.Tests.Classes.Connection
+{
+ [TestClass]
+ public class ProtocolVersionExchangeTest_ServerResponseValid_NoComments
+ {
+ private AsyncSocketListener _server;
+ private ProtocolVersionExchange _protocolVersionExchange;
+ private string _clientVersion;
+ private TimeSpan _timeout;
+ private IPEndPoint _serverEndPoint;
+ private List _dataReceivedByServer;
+ private byte[] _serverIdentification;
+ private bool _clientDisconnected;
+ private Socket _client;
+ private SshIdentification _actual;
+
+ [TestInitialize]
+ public void Setup()
+ {
+ Arrange();
+ Act();
+ }
+
+ [TestCleanup]
+ public void Cleanup()
+ {
+ if (_server != null)
+ {
+ _server.Dispose();
+ _server = null;
+ }
+
+ if (_client != null)
+ {
+ _client.Shutdown(SocketShutdown.Both);
+ _client.Close();
+ _client = null;
+ }
+ }
+
+ protected void Arrange()
+ {
+ _clientVersion = "SSH-2.0-Renci.SshNet.SshClient.0.0.1";
+ _timeout = TimeSpan.FromSeconds(5);
+ _serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
+ _dataReceivedByServer = new List();
+ _serverIdentification = Encoding.UTF8.GetBytes("Welcome stranger!\r\n\r\nSSH-Zero-OurSSHAppliance\r\n!");
+
+ _server = new AsyncSocketListener(_serverEndPoint);
+ _server.Start();
+ _server.BytesReceived += (bytes, socket) =>
+ {
+ _dataReceivedByServer.AddRange(bytes);
+ socket.Send(_serverIdentification);
+ socket.Shutdown(SocketShutdown.Send);
+ };
+ _server.Disconnected += (socket) => _clientDisconnected = true;
+
+ _client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ _client.Connect(_serverEndPoint);
+
+ _protocolVersionExchange = new ProtocolVersionExchange();
+ }
+
+ protected void Act()
+ {
+ _actual = _protocolVersionExchange.Start(_clientVersion, _client, _timeout);
+ }
+
+ [TestMethod]
+ public void StartShouldReturnIdentificationOfServer()
+ {
+ Assert.IsNotNull(_actual);
+ Assert.AreEqual("Zero", _actual.ProtocolVersion);
+ Assert.AreEqual("OurSSHAppliance", _actual.SoftwareVersion);
+ Assert.IsNull(_actual.Comments);
+ }
+
+ [TestMethod]
+ public void ClientIdentificationWasSentToServer()
+ {
+ var expected = Encoding.UTF8.GetBytes(_clientVersion);
+
+ Assert.AreEqual(expected.Length + 2, _dataReceivedByServer.Count);
+
+ Assert.IsTrue(expected.SequenceEqual(_dataReceivedByServer.Take(expected.Length)));
+ Assert.AreEqual(Session.CarriageReturn, _dataReceivedByServer[_dataReceivedByServer.Count - 2]);
+ Assert.AreEqual(Session.LineFeed, _dataReceivedByServer[_dataReceivedByServer.Count - 1]);
+ }
+
+ [TestMethod]
+ public void ClientRemainsConnected()
+ {
+ Assert.IsTrue(_client.Connected);
+ Assert.IsFalse(_clientDisconnected);
+ }
+
+ [TestMethod]
+ public void ClientDidNotReadPastIdentification()
+ {
+ var buffer = new byte[1];
+
+ var bytesReceived = _client.Receive(buffer);
+ Assert.AreEqual(1, bytesReceived);
+ Assert.AreEqual(0x21, buffer[0]);
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_TimeoutReadingIdentificationString.cs b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_TimeoutReadingIdentificationString.cs
new file mode 100644
index 00000000..6ef1668f
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_TimeoutReadingIdentificationString.cs
@@ -0,0 +1,113 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+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;
+using System.Text;
+
+namespace Renci.SshNet.Tests.Classes.Connection
+{
+ [TestClass]
+ public class ProtocolVersionExchangeTest_TimeoutReadingIdentificationString
+ {
+ private AsyncSocketListener _server;
+ private ProtocolVersionExchange _protocolVersionExchange;
+ private string _clientVersion;
+ private TimeSpan _timeout;
+ private IPEndPoint _serverEndPoint;
+ private List _dataReceivedByServer;
+ private bool _clientDisconnected;
+ private Socket _client;
+ private SshOperationTimeoutException _actualException;
+
+ [TestInitialize]
+ public void Setup()
+ {
+ Arrange();
+ Act();
+ }
+
+ [TestCleanup]
+ public void Cleanup()
+ {
+ if (_server != null)
+ {
+ _server.Dispose();
+ _server = null;
+ }
+
+ if (_client != null)
+ {
+ _client.Close();
+ _client = null;
+ }
+ }
+
+ protected void Arrange()
+ {
+ _clientVersion = "SSH-2.0-Renci.SshNet.SshClient.0.0.1";
+ _timeout = TimeSpan.FromMilliseconds(200);
+ _serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
+ _dataReceivedByServer = new List();
+ _clientDisconnected = false;
+
+ _server = new AsyncSocketListener(_serverEndPoint);
+ _server.Start();
+ _server.BytesReceived += (bytes, socket) =>
+ {
+ _dataReceivedByServer.AddRange(bytes);
+ socket.Send(Encoding.UTF8.GetBytes("Welcome!\r\n"));
+ };
+ _server.Disconnected += (socket) => _clientDisconnected = true;
+
+ _client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ _client.Connect(_serverEndPoint);
+
+ _protocolVersionExchange = new ProtocolVersionExchange();
+ }
+
+ protected void Act()
+ {
+ try
+ {
+ _protocolVersionExchange.Start(_clientVersion, _client, _timeout);
+ Assert.Fail();
+ }
+ catch (SshOperationTimeoutException ex)
+ {
+ _actualException = ex;
+ }
+ }
+
+ [TestMethod]
+ public void StartShouldHaveThrownSshOperationTimeoutException()
+ {
+ Assert.IsNotNull(_actualException);
+ Assert.IsNull(_actualException.InnerException);
+ Assert.AreEqual(string.Format("Socket read operation has timed out after {0} milliseconds.", _timeout.TotalMilliseconds), _actualException.Message);
+ }
+
+ [TestMethod]
+ public void ClientIdentificationWasSentToServer()
+ {
+ var expected = Encoding.UTF8.GetBytes(_clientVersion);
+
+ Assert.AreEqual(expected.Length + 2, _dataReceivedByServer.Count);
+
+ Assert.IsTrue(expected.SequenceEqual(_dataReceivedByServer.Take(expected.Length)));
+ Assert.AreEqual(Session.CarriageReturn, _dataReceivedByServer[_dataReceivedByServer.Count - 2]);
+ Assert.AreEqual(Session.LineFeed, _dataReceivedByServer[_dataReceivedByServer.Count - 1]);
+ }
+
+ [TestMethod]
+ public void ClientSocketShouldBeConnected()
+ {
+ Assert.IsTrue(_client.Connected);
+ Assert.IsFalse(_clientDisconnected);
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTestBase.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTestBase.cs
new file mode 100644
index 00000000..50f62256
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTestBase.cs
@@ -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 SocketFactoryMock { get; private set; }
+ internal Socks4Connector Connector { get; private set; }
+ internal SocketFactory SocketFactory { get; private set; }
+
+ protected virtual void CreateMocks()
+ {
+ SocketFactoryMock = new Mock(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"));
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionRejectedByProxy.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionRejectedByProxy.cs
new file mode 100644
index 00000000..3ef993f2
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionRejectedByProxy.cs
@@ -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 _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();
+ _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;
+ }
+ }
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionSucceeded.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionSucceeded.cs
new file mode 100644
index 00000000..9f184942
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionSucceeded.cs
@@ -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 _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();
+ _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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionToProxyRefused.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionToProxyRefused.cs
new file mode 100644
index 00000000..85f2f669
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionToProxyRefused.cs
@@ -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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutConnectingToProxy.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutConnectingToProxy.cs
new file mode 100644
index 00000000..4ce1560b
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutConnectingToProxy.cs
@@ -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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingDestinationAddress.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingDestinationAddress.cs
new file mode 100644
index 00000000..92840220
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingDestinationAddress.cs
@@ -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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyCode.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyCode.cs
new file mode 100644
index 00000000..bbc724ac
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyCode.cs
@@ -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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyVersion.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyVersion.cs
new file mode 100644
index 00000000..d2fcf5c1
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyVersion.cs
@@ -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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTestBase.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTestBase.cs
new file mode 100644
index 00000000..2d2f2cb9
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTestBase.cs
@@ -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 SocketFactoryMock { get; private set; }
+ internal Socks5Connector Connector { get; private set; }
+ internal SocketFactory SocketFactory { get; private set; }
+
+ protected virtual void CreateMocks()
+ {
+ SocketFactoryMock = new Mock(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();
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ConnectionToProxyRefused.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ConnectionToProxyRefused.cs
new file mode 100644
index 00000000..997c18a1
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ConnectionToProxyRefused.cs
@@ -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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_NoAuthentication_ConnectionSucceeded.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_NoAuthentication_ConnectionSucceeded.cs
new file mode 100644
index 00000000..7f4b108c
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_NoAuthentication_ConnectionSucceeded.cs
@@ -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 _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();
+
+ _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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ProxySocksVersionIsNotSupported.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ProxySocksVersionIsNotSupported.cs
new file mode 100644
index 00000000..dc9a3a9e
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ProxySocksVersionIsNotSupported.cs
@@ -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;
+ }
+ }
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_TimeoutConnectingToProxy.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_TimeoutConnectingToProxy.cs
new file mode 100644
index 00000000..4ac547b9
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_TimeoutConnectingToProxy.cs
@@ -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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_AuthenticationFailed.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_AuthenticationFailed.cs
new file mode 100644
index 00000000..878636ba
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_AuthenticationFailed.cs
@@ -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 _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();
+
+ _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();
+
+ //
+ // 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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_ConnectionSucceeded.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_ConnectionSucceeded.cs
new file mode 100644
index 00000000..b94c40e8
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_ConnectionSucceeded.cs
@@ -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 _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();
+
+ _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();
+
+ //
+ // 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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_PasswordExceedsMaximumLength.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_PasswordExceedsMaximumLength.cs
new file mode 100644
index 00000000..61db86a4
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_PasswordExceedsMaximumLength.cs
@@ -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 _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();
+ _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();
+
+ //
+ // 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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_UserNameExceedsMaximumLength.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_UserNameExceedsMaximumLength.cs
new file mode 100644
index 00000000..7a0ef5d4
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_UserNameExceedsMaximumLength.cs
@@ -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 _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();
+ _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();
+
+ //
+ // 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());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Connection/SshIdentificationTest.cs b/src/Renci.SshNet.Tests/Classes/Connection/SshIdentificationTest.cs
new file mode 100644
index 00000000..2a7137ae
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/Connection/SshIdentificationTest.cs
@@ -0,0 +1,139 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Connection;
+using System;
+
+namespace Renci.SshNet.Tests.Classes.Connection
+{
+ [TestClass]
+ public class SshIdentificationTest
+ {
+ [TestMethod]
+ public void Ctor_ProtocolVersionAndSoftwareVersion()
+ {
+ const string protocolVersion = "1.5";
+ const string softwareVersion = "SSH.NET_2020.0.0";
+
+ var sshIdentification = new SshIdentification(protocolVersion, softwareVersion);
+ Assert.AreSame(protocolVersion, sshIdentification.ProtocolVersion);
+ Assert.AreSame(softwareVersion, sshIdentification.SoftwareVersion);
+ Assert.IsNull(sshIdentification.Comments);
+ }
+
+ [TestMethod]
+ public void Ctor_ProtocolVersionAndSoftwareVersion_ProtocolVersionIsNull()
+ {
+ const string protocolVersion = null;
+ const string softwareVersion = "SSH.NET_2020.0.0";
+
+ try
+ {
+ new SshIdentification(protocolVersion, softwareVersion);
+ Assert.Fail();
+ }
+ catch (ArgumentNullException ex)
+ {
+ Assert.IsNull(ex.InnerException);
+ Assert.AreEqual("protocolVersion", ex.ParamName);
+ }
+ }
+
+ [TestMethod]
+ public void Ctor_ProtocolVersionAndSoftwareVersion_SoftwareVersionIsNull()
+ {
+ const string protocolVersion = "2.0";
+ const string softwareVersion = null;
+
+ try
+ {
+ new SshIdentification(protocolVersion, softwareVersion);
+ Assert.Fail();
+ }
+ catch (ArgumentNullException ex)
+ {
+ Assert.IsNull(ex.InnerException);
+ Assert.AreEqual("softwareVersion", ex.ParamName);
+ }
+ }
+
+ [TestMethod]
+ public void Ctor_ProtocolVersionAndSoftwareVersionAndComments()
+ {
+ const string protocolVersion = "1.5";
+ const string softwareVersion = "SSH.NET_2020.0.0";
+ const string comments = "Beware, dangerous!";
+
+ var sshIdentification = new SshIdentification(protocolVersion, softwareVersion, comments);
+ Assert.AreSame(protocolVersion, sshIdentification.ProtocolVersion);
+ Assert.AreSame(softwareVersion, sshIdentification.SoftwareVersion);
+ Assert.AreSame(comments, sshIdentification.Comments);
+ }
+
+ [TestMethod]
+ public void Ctor_ProtocolVersionAndSoftwareVersionAndComments_CommentsIsNull()
+ {
+ const string protocolVersion = "1.5";
+ const string softwareVersion = "SSH.NET_2020.0.0";
+ const string comments = null;
+
+ var sshIdentification = new SshIdentification(protocolVersion, softwareVersion, comments);
+ Assert.AreSame(protocolVersion, sshIdentification.ProtocolVersion);
+ Assert.AreSame(softwareVersion, sshIdentification.SoftwareVersion);
+ Assert.IsNull(comments, sshIdentification.Comments);
+ }
+
+ [TestMethod]
+ public void Ctor_ProtocolVersionAndSoftwareVersionAndComments_ProtocolVersionIsNull()
+ {
+ const string protocolVersion = null;
+ const string softwareVersion = "SSH.NET_2020.0.0";
+ const string comments = "Beware!";
+
+ try
+ {
+ new SshIdentification(protocolVersion, softwareVersion, comments);
+ Assert.Fail();
+ }
+ catch (ArgumentNullException ex)
+ {
+ Assert.IsNull(ex.InnerException);
+ Assert.AreEqual("protocolVersion", ex.ParamName);
+ }
+ }
+
+ [TestMethod]
+ public void Ctor_ProtocolVersionAndSoftwareVersionAndComments_SoftwareVersionIsNull()
+ {
+ const string protocolVersion = "2.0";
+ const string softwareVersion = null;
+ const string comments = "Beware!";
+
+ try
+ {
+ new SshIdentification(protocolVersion, softwareVersion, comments);
+ Assert.Fail();
+ }
+ catch (ArgumentNullException ex)
+ {
+ Assert.IsNull(ex.InnerException);
+ Assert.AreEqual("softwareVersion", ex.ParamName);
+ }
+ }
+
+ [TestMethod]
+ public void ToString_Comments()
+ {
+ var sshIdentification = new SshIdentification("2.0", "SSH.NET", "Beware, dangerous");
+ Assert.AreEqual("SSH-2.0-SSH.NET Beware, dangerous", sshIdentification.ToString());
+ }
+
+ [TestMethod]
+ public void ToString_CommentsIsNull()
+ {
+ var sshIdentification = new SshIdentification("2.0", "SSH.NET_2020.0.0");
+ Assert.AreEqual("SSH-2.0-SSH.NET_2020.0.0", sshIdentification.ToString());
+
+ sshIdentification = new SshIdentification("2.0", "SSH.NET_2020.0.0", null);
+ Assert.AreEqual("SSH-2.0-SSH.NET_2020.0.0", sshIdentification.ToString());
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelExtendedDataMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelExtendedDataMessageTest.cs
index e50f5fa4..469908ea 100644
--- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelExtendedDataMessageTest.cs
+++ b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelExtendedDataMessageTest.cs
@@ -30,7 +30,7 @@ namespace Renci.SshNet.Tests.Classes.Messages.Connection
[Ignore] // placeholder
public void ChannelExtendedDataMessageConstructorTest1()
{
- uint localChannelNumber = 0; // TODO: Initialize to an appropriate value
+ //uint localChannelNumber = 0; // TODO: Initialize to an appropriate value
//ChannelExtendedDataMessage target = new ChannelExtendedDataMessage(localChannelNumber, null, null);
Assert.Inconclusive("TODO: Implement code to verify target");
}
diff --git a/src/Renci.SshNet.Tests/Classes/NetConfClientTestBase.cs b/src/Renci.SshNet.Tests/Classes/NetConfClientTestBase.cs
new file mode 100644
index 00000000..ee8cb018
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/NetConfClientTestBase.cs
@@ -0,0 +1,17 @@
+using Moq;
+using Renci.SshNet.NetConf;
+
+namespace Renci.SshNet.Tests.Classes
+{
+ public abstract class NetConfClientTestBase : BaseClientTestBase
+ {
+ internal Mock _netConfSessionMock { get; private set; }
+
+ protected override void CreateMocks()
+ {
+ base.CreateMocks();
+
+ _netConfSessionMock = new Mock(MockBehavior.Strict);
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs
index 64ffb6ce..980c574a 100644
--- a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs
+++ b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs
@@ -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 _serviceFactoryMock;
- private Mock _sessionMock;
- private Mock _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(MockBehavior.Strict);
- _sessionMock = new Mock(MockBehavior.Strict);
- _netConfSessionMock = new Mock(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
{
diff --git a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Connected.cs b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Connected.cs
index ad0cf531..ba86a7c9 100644
--- a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Connected.cs
+++ b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Connected.cs
@@ -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 _serviceFactoryMock;
- private Mock _sessionMock;
- private Mock _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(MockBehavior.Strict);
- _sessionMock = new Mock(MockBehavior.Strict);
- _netConfSessionMock = new Mock(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]
diff --git a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disconnected.cs b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disconnected.cs
index 24b495d7..8a4fbcd2 100644
--- a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disconnected.cs
+++ b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disconnected.cs
@@ -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 _serviceFactoryMock;
- private Mock _sessionMock;
- private Mock _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(MockBehavior.Strict);
- _sessionMock = new Mock(MockBehavior.Strict);
- _netConfSessionMock = new Mock(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]
diff --git a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disposed.cs b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disposed.cs
index 7439ed75..9ed692a3 100644
--- a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disposed.cs
+++ b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disposed.cs
@@ -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 _serviceFactoryMock;
- private Mock _sessionMock;
- private Mock _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(MockBehavior.Strict);
- _sessionMock = new Mock(MockBehavior.Strict);
- _netConfSessionMock = new Mock(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]
diff --git a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Finalize_Connected.cs b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Finalize_Connected.cs
index fb17e353..44761e96 100644
--- a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Finalize_Connected.cs
+++ b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Finalize_Connected.cs
@@ -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 _serviceFactoryMock;
- private Mock _sessionMock;
- private Mock _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(MockBehavior.Loose);
- _sessionMock = new Mock(MockBehavior.Loose);
- _netConfSessionMock = new Mock(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);
+ }
}
}
diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTestBase.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTestBase.cs
index 8626d7d0..26aa22e3 100644
--- a/src/Renci.SshNet.Tests/Classes/ScpClientTestBase.cs
+++ b/src/Renci.SshNet.Tests/Classes/ScpClientTestBase.cs
@@ -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 _serviceFactoryMock;
internal Mock _remotePathTransformationMock;
- internal Mock _sessionMock;
internal Mock _channelSessionMock;
internal Mock _pipeStreamMock;
- protected abstract void SetupData();
-
- protected void CreateMocks()
+ protected override void CreateMocks()
{
- _serviceFactoryMock = new Mock(MockBehavior.Strict);
+ base.CreateMocks();
+
_remotePathTransformationMock = new Mock(MockBehavior.Strict);
- _sessionMock = new Mock(MockBehavior.Strict);
_channelSessionMock = new Mock(MockBehavior.Strict);
_pipeStreamMock = new Mock(MockBehavior.Strict);
}
-
- protected abstract void SetupMocks();
-
- protected virtual void Arrange()
- {
- SetupData();
- CreateMocks();
- SetupMocks();
- }
-
- [TestInitialize]
- public void Initialize()
- {
- Arrange();
- Act();
- }
-
- protected abstract void Act();
}
}
diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs
index aa5d5cfb..9c5ed485 100644
--- a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs
+++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs
@@ -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);
@@ -52,6 +55,10 @@ namespace Renci.SshNet.Tests.Classes
.Returns(false);
_channelSessionMock.InSequence(sequence).Setup(p => p.Dispose());
_pipeStreamMock.As().InSequence(sequence).Setup(p => p.Dispose());
+
+ // On .NET Core, Dispose() in turn invokes Close() and since we're not mocking
+ // an interface, we need to expect this call as well
+ _pipeStreamMock.Setup(p => p.Close());
}
protected override void Arrange()
diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse.cs
index 80165725..8ba4525b 100644
--- a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse.cs
+++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse.cs
@@ -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);
@@ -51,6 +54,10 @@ namespace Renci.SshNet.Tests.Classes
.Setup(p => p.SendExecRequest(string.Format("scp -pf {0}", _transformedPath))).Returns(false);
_channelSessionMock.InSequence(sequence).Setup(p => p.Dispose());
_pipeStreamMock.As().InSequence(sequence).Setup(p => p.Dispose());
+
+ // On .NET Core, Dispose() in turn invokes Close() and since we're not mocking
+ // an interface, we need to expect this call as well
+ _pipeStreamMock.Setup(p => p.Close());
}
protected override void Arrange()
diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse.cs
index 309e4566..c1504aec 100644
--- a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse.cs
+++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse.cs
@@ -19,15 +19,6 @@ namespace Renci.SshNet.Tests.Classes
private IList _uploadingRegister;
private SshException _actualException;
- [TestCleanup]
- public void Cleanup()
- {
- if (_destination != null)
- {
- _destination.Dispose();
- }
- }
-
protected override void SetupData()
{
var random = new Random();
@@ -47,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);
@@ -61,6 +55,10 @@ namespace Renci.SshNet.Tests.Classes
.Returns(false);
_channelSessionMock.InSequence(sequence).Setup(p => p.Dispose());
_pipeStreamMock.As().InSequence(sequence).Setup(p => p.Dispose());
+
+ // On .NET Core, Dispose() in turn invokes Close() and since we're not mocking
+ // an interface, we need to expect this call as well
+ _pipeStreamMock.Setup(p => p.Close());
}
protected override void Arrange()
@@ -72,6 +70,16 @@ namespace Renci.SshNet.Tests.Classes
_scpClient.Connect();
}
+ protected override void TearDown()
+ {
+ base.TearDown();
+
+ if (_destination != null)
+ {
+ _destination.Dispose();
+ }
+ }
+
protected override void Act()
{
try
diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs
index 1c47aeae..6791e296 100644
--- a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs
+++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs
@@ -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);
@@ -51,6 +54,10 @@ namespace Renci.SshNet.Tests.Classes
.Returns(false);
_channelSessionMock.InSequence(sequence).Setup(p => p.Dispose());
_pipeStreamMock.As().InSequence(sequence).Setup(p => p.Dispose());
+
+ // On .NET Core, Dispose() in turn invokes Close() and since we're not mocking
+ // an interface, we need to expect this call as well
+ _pipeStreamMock.Setup(p => p.Close());
}
protected override void Arrange()
diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs
index 0c842a21..9a065ee2 100644
--- a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs
+++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs
@@ -21,16 +21,6 @@ namespace Renci.SshNet.Tests.Classes
private IList _uploadingRegister;
private SshException _actualException;
- [TestCleanup]
- public void Cleanup()
- {
- if (_fileName != null)
- {
- File.Delete(_fileName);
- _fileName = null;
- }
- }
-
protected override void SetupData()
{
var random = new Random();
@@ -53,7 +43,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);
@@ -67,7 +60,11 @@ namespace Renci.SshNet.Tests.Classes
.Returns(false);
_channelSessionMock.InSequence(sequence).Setup(p => p.Dispose());
_pipeStreamMock.As().InSequence(sequence).Setup(p => p.Dispose());
- }
+
+ // On .NET Core, Dispose() in turn invokes Close() and since we're not mocking
+ // an interface, we need to expect this call as well
+ _pipeStreamMock.Setup(p => p.Close());
+}
protected override void Arrange()
{
@@ -78,6 +75,17 @@ namespace Renci.SshNet.Tests.Classes
_scpClient.Connect();
}
+ protected override void TearDown()
+ {
+ base.TearDown();
+
+ if (_fileName != null)
+ {
+ File.Delete(_fileName);
+ _fileName = null;
+ }
+ }
+
protected override void Act()
{
try
diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_Success.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_Success.cs
index c04525e0..d86191e5 100644
--- a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_Success.cs
+++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_Success.cs
@@ -25,16 +25,6 @@ namespace Renci.SshNet.Tests.Classes
private int _fileSize;
private IList _uploadingRegister;
- [TestCleanup]
- public void Cleanup()
- {
- if (_fileName != null)
- {
- File.Delete(_fileName);
- _fileName = null;
- }
- }
-
protected override void SetupData()
{
var random = new Random();
@@ -60,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);
@@ -92,6 +85,10 @@ namespace Renci.SshNet.Tests.Classes
_pipeStreamMock.InSequence(sequence).Setup(p => p.ReadByte()).Returns(0);
_channelSessionMock.InSequence(sequence).Setup(p => p.Dispose());
_pipeStreamMock.As().InSequence(sequence).Setup(p => p.Dispose());
+
+ // On .NET Core, Dispose() in turn invokes Close() and since we're not mocking
+ // an interface, we need to expect this call as well
+ _pipeStreamMock.Setup(p => p.Close());
}
protected override void Arrange()
@@ -106,6 +103,17 @@ namespace Renci.SshNet.Tests.Classes
_scpClient.Connect();
}
+ protected override void TearDown()
+ {
+ base.TearDown();
+
+ if (_fileName != null)
+ {
+ File.Delete(_fileName);
+ _fileName = null;
+ }
+ }
+
protected override void Act()
{
_scpClient.Upload(_fileInfo, _remotePath);
diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs
index d2c6992b..5facca29 100644
--- a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs
+++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs
@@ -20,15 +20,6 @@ namespace Renci.SshNet.Tests.Classes
private IList _uploadingRegister;
private SshException _actualException;
- [TestCleanup]
- public void Cleanup()
- {
- if (_source != null)
- {
- _source.Dispose();
- }
- }
-
protected override void SetupData()
{
var random = new Random();
@@ -50,7 +41,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);
@@ -64,6 +58,10 @@ namespace Renci.SshNet.Tests.Classes
.Returns(false);
_channelSessionMock.InSequence(sequence).Setup(p => p.Dispose());
_pipeStreamMock.As().InSequence(sequence).Setup(p => p.Dispose());
+
+ // On .NET Core, Dispose() in turn invokes Close() and since we're not mocking
+ // an interface, we need to expect this call as well
+ _pipeStreamMock.Setup(p => p.Close());
}
protected override void Arrange()
@@ -75,6 +73,16 @@ namespace Renci.SshNet.Tests.Classes
_scpClient.Connect();
}
+ protected override void TearDown()
+ {
+ base.TearDown();
+
+ if (_source != null)
+ {
+ _source.Dispose();
+ }
+ }
+
protected override void Act()
{
try
diff --git a/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateConnector.cs b/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateConnector.cs
new file mode 100644
index 00000000..22d2d4c0
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateConnector.cs
@@ -0,0 +1,140 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Connection;
+using System;
+
+namespace Renci.SshNet.Tests.Classes
+{
+ [TestClass]
+ public class ServiceFactoryTest_CreateConnector
+ {
+ private ServiceFactory _serviceFactory;
+ private Mock _connectionInfoMock;
+ private Mock _socketFactoryMock;
+
+ [TestInitialize]
+ public void Setup()
+ {
+ _serviceFactory = new ServiceFactory();
+ _connectionInfoMock = new Mock(MockBehavior.Strict);
+ _socketFactoryMock = new Mock(MockBehavior.Strict);
+ }
+
+ [TestMethod]
+ public void ConnectionInfoIsNull()
+ {
+ const IConnectionInfo connectionInfo = null;
+
+ try
+ {
+ _serviceFactory.CreateConnector(connectionInfo, _socketFactoryMock.Object);
+ Assert.Fail();
+ }
+ catch (ArgumentNullException ex)
+ {
+ Assert.IsNull(ex.InnerException);
+ Assert.AreEqual("connectionInfo", ex.ParamName);
+ }
+ }
+
+ [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, _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);
+ }
+
+ [TestMethod]
+ public void ProxyType_None()
+ {
+ _connectionInfoMock.Setup(p => p.ProxyType).Returns(ProxyTypes.None);
+
+ 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);
+ }
+
+ [TestMethod]
+ public void ProxyType_Socks4()
+ {
+ _connectionInfoMock.Setup(p => p.ProxyType).Returns(ProxyTypes.Socks4);
+
+ 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);
+ }
+
+ [TestMethod]
+ public void ProxyType_Socks5()
+ {
+ _connectionInfoMock.Setup(p => p.ProxyType).Returns(ProxyTypes.Socks5);
+
+ 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.Exactly(2));
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest.HttpProxy.cs b/src/Renci.SshNet.Tests/Classes/SessionTest.HttpProxy.cs
index 7780d2d8..03ce2491 100644
--- a/src/Renci.SshNet.Tests/Classes/SessionTest.HttpProxy.cs
+++ b/src/Renci.SshNet.Tests/Classes/SessionTest.HttpProxy.cs
@@ -5,240 +5,13 @@ using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Renci.SshNet.Common;
using Renci.SshNet.Tests.Common;
+using Renci.SshNet.Connection;
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();
-
- using (var session = new Session(CreateConnectionInfoWithProxy(proxyEndPoint, serverEndPoint, "anon"), _serviceFactoryMock.Object))
- {
- 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();
-
- using (var session = new Session(CreateConnectionInfoWithProxy(proxyEndPoint, serverEndPoint, "anon"), _serviceFactoryMock.Object))
- {
- 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();
-
- using (var session = new Session(CreateConnectionInfoWithProxy(proxyEndPoint, serverEndPoint, "anon"), _serviceFactoryMock.Object))
- {
- 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();
-
- using (var session = new Session(CreateConnectionInfoWithProxy(proxyEndPoint, serverEndPoint, "anon"), _serviceFactoryMock.Object))
- {
- 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();
-
- using (var session = new Session(CreateConnectionInfoWithProxy(proxyEndPoint, serverEndPoint, "anon"), _serviceFactoryMock.Object))
- {
- 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 = CreateConnectionInfoWithProxy(proxyEndPoint, serverEndPoint, "anon");
- using (var session = new Session(connectionInfo, _serviceFactoryMock.Object))
- {
- 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 = CreateConnectionInfoWithProxy(proxyEndPoint, serverEndPoint, string.Empty);
- using (var session = new Session(connectionInfo, _serviceFactoryMock.Object))
- {
- 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 = CreateConnectionInfoWithProxy(proxyEndPoint, serverEndPoint, null);
- using (var session = new Session(connectionInfo, _serviceFactoryMock.Object))
- {
- try
- {
- session.Connect();
- Assert.Fail();
- }
- catch (ProxyException)
- {
- }
- }
-
- Assert.IsFalse(proxyStub.HttpRequest.Headers.Any(p => p.StartsWith("Proxy-Authorization:")));
- }
- }
-
- private static ConnectionInfo CreateConnectionInfoWithProxy(IPEndPoint proxyEndPoint, IPEndPoint serverEndPoint, string proxyUserName)
+ private static ConnectionInfo CreateConnectionInfoWithHttpProxy(IPEndPoint proxyEndPoint, IPEndPoint serverEndPoint, string proxyUserName)
{
return new ConnectionInfo(
serverEndPoint.Address.ToString(),
diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest.cs b/src/Renci.SshNet.Tests/Classes/SessionTest.cs
index de523769..972757e4 100644
--- a/src/Renci.SshNet.Tests/Classes/SessionTest.cs
+++ b/src/Renci.SshNet.Tests/Classes/SessionTest.cs
@@ -1,15 +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.Messages.Transport;
+using Renci.SshNet.Connection;
using Renci.SshNet.Tests.Common;
-using Renci.SshNet.Tests.Properties;
namespace Renci.SshNet.Tests.Classes
{
@@ -20,23 +14,28 @@ namespace Renci.SshNet.Tests.Classes
public partial class SessionTest : TestBase
{
private Mock _serviceFactoryMock;
+ private Mock _socketFactoryMock;
+ private Mock _connectorMock;
+ private Mock _protocolVersionExchangeMock;
protected override void OnInit()
{
base.OnInit();
_serviceFactoryMock = new Mock(MockBehavior.Strict);
+ _socketFactoryMock = new Mock(MockBehavior.Strict);
+ _connectorMock = new Mock(MockBehavior.Strict);
+ _protocolVersionExchangeMock = new Mock(MockBehavior.Strict);
}
[TestMethod]
public void ConstructorShouldThrowArgumentNullExceptionWhenConnectionInfoIsNull()
{
- ConnectionInfo connectionInfo = null;
- var serviceFactory = new Mock(MockBehavior.Strict).Object;
+ const ConnectionInfo connectionInfo = null;
try
{
- new Session(connectionInfo, serviceFactory);
+ new Session(connectionInfo, _serviceFactoryMock.Object, _socketFactoryMock.Object);
Assert.Fail();
}
catch (ArgumentNullException ex)
@@ -55,7 +54,7 @@ namespace Renci.SshNet.Tests.Classes
try
{
- new Session(connectionInfo, serviceFactory);
+ new Session(connectionInfo, serviceFactory, _socketFactoryMock.Object);
Assert.Fail();
}
catch (ArgumentNullException ex)
@@ -66,338 +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))
- {
- 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))
- {
- 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))
- {
- 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();
-
- using (var session = new Session(CreateConnectionInfo(serverEndPoint, TimeSpan.FromMilliseconds(500)), _serviceFactoryMock.Object))
- {
- 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();
-
- using (var session = new Session(CreateConnectionInfo(serverEndPoint, TimeSpan.FromSeconds(5)), _serviceFactoryMock.Object))
- {
- 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();
-
- using (var session = new Session(CreateConnectionInfo(serverEndPoint, TimeSpan.FromSeconds(5)), _serviceFactoryMock.Object))
- {
- 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();
-
- using (var session = new Session(CreateConnectionInfo(serverEndPoint, TimeSpan.FromSeconds(5)), _serviceFactoryMock.Object))
- {
- 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);
+ 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);
-
- 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);
-
- 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);
-
- 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(
diff --git a/src/Renci.SshNet.Tests/Classes/SessionTestBase.cs b/src/Renci.SshNet.Tests/Classes/SessionTestBase.cs
new file mode 100644
index 00000000..cbe69e2a
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/SessionTestBase.cs
@@ -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 _serviceFactoryMock { get; private set; }
+ internal Mock _socketFactoryMock { get; private set; }
+ internal Mock _connectorMock { get; private set; }
+
+ protected virtual void CreateMocks()
+ {
+ _serviceFactoryMock = new Mock(MockBehavior.Strict);
+ _socketFactoryMock = new Mock(MockBehavior.Strict);
+ _connectorMock = new Mock(MockBehavior.Strict);
+ }
+
+ protected virtual void SetupData()
+ {
+ }
+
+ protected virtual void SetupMocks()
+ {
+ }
+
+ protected override void Arrange()
+ {
+ CreateMocks();
+ SetupData();
+ SetupMocks();
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_ConnectToServerFails.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_ConnectToServerFails.cs
new file mode 100644
index 00000000..df19c8ec
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/SessionTest_ConnectToServerFails.cs
@@ -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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected.cs
index 0d8f2412..fa36aed5 100644
--- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected.cs
+++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected.cs
@@ -1,6 +1,7 @@
using System;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
using Renci.SshNet.Messages.Transport;
namespace Renci.SshNet.Tests.Classes
@@ -65,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]
@@ -251,5 +252,24 @@ namespace Renci.SshNet.Tests.Classes
Assert.IsNull(exception);
}
}
+
+ [TestMethod]
+ public void ClientSocketShouldBeConnected()
+ {
+ Assert.IsNotNull(ClientSocket);
+ Assert.IsTrue(ClientSocket.Connected);
+ }
+
+ [TestMethod]
+ public void CreateConnectorOnServiceFactoryShouldHaveBeenInvokedOnce()
+ {
+ ServiceFactoryMock.Verify(p => p.CreateConnector(ConnectionInfo, SocketFactoryMock.Object), Times.Once());
+ }
+
+ [TestMethod]
+ public void ConnectorOnConnectorShouldHaveBeenInvokedOnce()
+ {
+ ConnectorMock.Verify(p => p.Connect(ConnectionInfo), Times.Once());
+ }
}
}
\ No newline at end of file
diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs
index 3e42dac1..a920b190 100644
--- a/src/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs
+++ b/src/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs
@@ -9,6 +9,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using Renci.SshNet.Compression;
+using Renci.SshNet.Connection;
using Renci.SshNet.Messages;
using Renci.SshNet.Messages.Transport;
using Renci.SshNet.Security;
@@ -20,11 +21,17 @@ namespace Renci.SshNet.Tests.Classes
[TestClass]
public abstract class SessionTest_ConnectedBase
{
- private Mock _serviceFactoryMock;
+ internal Mock ServiceFactoryMock { get; private set; }
+ internal Mock SocketFactoryMock { get; private set; }
+ internal Mock ConnectorMock { get; private set; }
+
+ private Mock _protocolVersionExchangeMock;
private Mock _keyExchangeMock;
private Mock _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; }
@@ -35,7 +42,9 @@ namespace Renci.SshNet.Tests.Classes
protected AsyncSocketListener ServerListener { get; private set; }
protected IList 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; }
[TestInitialize]
public void Setup()
@@ -64,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()
@@ -84,8 +99,11 @@ namespace Renci.SshNet.Tests.Classes
DisconnectReceivedRegister = new List>();
ErrorOccurredRegister = new List();
ServerBytesReceivedRegister = new List();
+ 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);
@@ -102,56 +120,65 @@ 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(MockBehavior.Strict);
+ ServiceFactoryMock = new Mock(MockBehavior.Strict);
+ SocketFactoryMock = new Mock(MockBehavior.Strict);
+ ConnectorMock = new Mock(MockBehavior.Strict);
+ _protocolVersionExchangeMock = new Mock(MockBehavior.Strict);
_keyExchangeMock = new Mock(MockBehavior.Strict);
_clientAuthenticationMock = new Mock(MockBehavior.Strict);
}
private void SetupMocks()
{
- _serviceFactoryMock.Setup(
+ ServiceFactoryMock.Setup(p => p.CreateConnector(ConnectionInfo, SocketFactoryMock.Object))
+ .Returns(ConnectorMock.Object);
+ ConnectorMock.Setup(p => p.Connect(ConnectionInfo))
+ .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);
_keyExchangeMock.Setup(p => p.Name).Returns(_keyExchangeAlgorithm);
@@ -164,19 +191,18 @@ namespace Renci.SshNet.Tests.Classes
_keyExchangeMock.Setup(p => p.CreateCompressor()).Returns((Compressor) null);
_keyExchangeMock.Setup(p => p.CreateDecompressor()).Returns((Compressor) null);
_keyExchangeMock.Setup(p => p.Dispose());
- _serviceFactoryMock.Setup(p => p.CreateClientAuthentication())
+ ServiceFactoryMock.Setup(p => p.CreateClientAuthentication())
.Callback(ClientAuthentication_Callback)
.Returns(_clientAuthenticationMock.Object);
_clientAuthenticationMock.Setup(p => p.Authenticate(ConnectionInfo, Session));
}
- protected virtual void Arrange()
+ protected void Arrange()
{
CreateMocks();
SetupData();
SetupMocks();
- ServerListener.Start();
Session.Connect();
}
diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_Disconnect.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_Disconnect.cs
index 3aed3027..eacb27c3 100644
--- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_Disconnect.cs
+++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_Disconnect.cs
@@ -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);
+ }
}
}
\ No newline at end of file
diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_GlobalRequestMessageAfterAuthenticationRace.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_GlobalRequestMessageAfterAuthenticationRace.cs
index a78154f7..a8ce5c96 100644
--- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_GlobalRequestMessageAfterAuthenticationRace.cs
+++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_GlobalRequestMessageAfterAuthenticationRace.cs
@@ -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());
}
}
}
diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerAndClientDisconnectRace.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerAndClientDisconnectRace.cs
index 5729c022..68bcbdaa 100644
--- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerAndClientDisconnectRace.cs
+++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerAndClientDisconnectRace.cs
@@ -4,11 +4,11 @@ using System.Globalization;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
-using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Common;
using Renci.SshNet.Compression;
+using Renci.SshNet.Connection;
using Renci.SshNet.Messages;
using Renci.SshNet.Messages.Transport;
using Renci.SshNet.Security;
@@ -21,11 +21,16 @@ namespace Renci.SshNet.Tests.Classes
public class SessionTest_Connected_ServerAndClientDisconnectRace
{
private Mock _serviceFactoryMock;
+ private Mock _socketFactoryMock;
+ private Mock _connectorMock;
+ private Mock _protocolVersionExchangeMock;
private Mock _keyExchangeMock;
private Mock _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; }
@@ -36,7 +41,9 @@ namespace Renci.SshNet.Tests.Classes
protected AsyncSocketListener ServerListener { get; private set; }
protected IList 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()
{
@@ -49,6 +56,12 @@ namespace Renci.SshNet.Tests.Classes
{
Session.Dispose();
}
+
+ if (ClientSocket != null && ClientSocket.Connected)
+ {
+ ClientSocket.Shutdown(SocketShutdown.Both);
+ ClientSocket.Dispose();
+ }
}
protected virtual void SetupData()
@@ -69,39 +82,31 @@ namespace Renci.SshNet.Tests.Classes
DisconnectReceivedRegister = new List>();
ErrorOccurredRegister = new List();
ServerBytesReceivedRegister = new List();
+ 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
+ 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],
@@ -114,26 +119,46 @@ namespace Renci.SshNet.Tests.Classes
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 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(MockBehavior.Strict);
+ _socketFactoryMock = new Mock(MockBehavior.Strict);
+ _connectorMock = new Mock(MockBehavior.Strict);
+ _protocolVersionExchangeMock = new Mock(MockBehavior.Strict);
_keyExchangeMock = new Mock(MockBehavior.Strict);
_clientAuthenticationMock = new Mock(MockBehavior.Strict);
}
private void SetupMocks()
{
+ _serviceFactoryMock.Setup(p => p.CreateConnector(ConnectionInfo, _socketFactoryMock.Object))
+ .Returns(_connectorMock.Object);
+ _connectorMock.Setup(p => p.Connect(ConnectionInfo))
+ .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);
@@ -157,7 +182,6 @@ namespace Renci.SshNet.Tests.Classes
SetupData();
SetupMocks();
- ServerListener.Start();
Session.Connect();
}
diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessage.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessage.cs
index 1b887dc6..36a73d82 100644
--- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessage.cs
+++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessage.cs
@@ -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]
diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessageAndShutsDownSocket.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessageAndShutsDownSocket.cs
index d8a50a3d..f3bb9877 100644
--- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessageAndShutsDownSocket.cs
+++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessageAndShutsDownSocket.cs
@@ -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]
diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsUnsupportedMessageType.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsUnsupportedMessageType.cs
index 02e998a4..a40f6e03 100644
--- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsUnsupportedMessageType.cs
+++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsUnsupportedMessageType.cs
@@ -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);
diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_NotConnected.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_NotConnected.cs
index 4a8b3ded..97a49a0e 100644
--- a/src/Renci.SshNet.Tests/Classes/SessionTest_NotConnected.cs
+++ b/src/Renci.SshNet.Tests/Classes/SessionTest_NotConnected.cs
@@ -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(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()
{
diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_SocketConnected_BadPacketAndDispose.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_SocketConnected_BadPacketAndDispose.cs
index a13de281..f5fb4d79 100644
--- a/src/Renci.SshNet.Tests/Classes/SessionTest_SocketConnected_BadPacketAndDispose.cs
+++ b/src/Renci.SshNet.Tests/Classes/SessionTest_SocketConnected_BadPacketAndDispose.cs
@@ -1,10 +1,10 @@
using System;
using System.Net;
using System.Net.Sockets;
-using System.Text;
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;
@@ -14,12 +14,17 @@ namespace Renci.SshNet.Tests.Classes
public class SessionTest_SocketConnected_BadPacketAndDispose
{
private Mock _serviceFactoryMock;
+ private Mock _socketFactoryMock;
+ private Mock _connectorMock;
+ private Mock _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()
@@ -37,7 +42,15 @@ namespace Renci.SshNet.Tests.Classes
}
}
- protected void Arrange()
+ protected void CreateMocks()
+ {
+ _serviceFactoryMock = new Mock(MockBehavior.Strict);
+ _socketFactoryMock = new Mock(MockBehavior.Strict);
+ _connectorMock = new Mock(MockBehavior.Strict);
+ _protocolVersionExchangeMock = new Mock(MockBehavior.Strict);
+ }
+
+ protected void SetupData()
{
_serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
_connectionInfo = new ConnectionInfo(
@@ -47,32 +60,51 @@ namespace Renci.SshNet.Tests.Classes
new PasswordAuthenticationMethod("user", "password"));
_connectionInfo.Timeout = TimeSpan.FromMilliseconds(200);
_actualException = null;
-
- _serviceFactoryMock = new Mock(MockBehavior.Strict);
+ _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) =>
- {
- var badPacket = new byte[] {0x0a, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05};
+ // 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, _socketFactoryMock.Object))
+ .Returns(_connectorMock.Object);
+ _connectorMock.Setup(p => p.Connect(_connectionInfo))
+ .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()
+ {
+ CreateMocks();
+ SetupData();
+ SetupMocks();
}
protected virtual void Act()
{
try
{
- using (_session = new Session(_connectionInfo, _serviceFactoryMock.Object))
+
{
_session.Connect();
}
diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTestBase.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTestBase.cs
index fe73f9a6..2f2f1bbf 100644
--- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTestBase.cs
+++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTestBase.cs
@@ -38,7 +38,8 @@ namespace Renci.SshNet.Tests.Classes.Sftp
protected static SftpFileAttributes CreateSftpFileAttributes(long size)
{
- return new SftpFileAttributes(default(DateTime), default(DateTime), size, default(int), default(int), default(uint), null);
+ var utcDefault = DateTime.SpecifyKind(default(DateTime), DateTimeKind.Utc);
+ return new SftpFileAttributes(utcDefault, utcDefault, size, default(int), default(int), default(uint), null);
}
protected static byte[] CreateByteArray(Random random, int length)
diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessRead.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessRead.cs
index 002b97b0..aaa62c85 100644
--- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessRead.cs
+++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessRead.cs
@@ -24,7 +24,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp
var random = new Random();
_path = random.Next().ToString();
_handle = GenerateRandom(3, random);
- _bufferSize = (uint) random.Next(0, 1000);
+ _bufferSize = (uint) random.Next(1, 1000);
_readBufferSize = (uint) random.Next(0, 1000);
_writeBufferSize = (uint) random.Next(0, 1000);
}
diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessWrite.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessWrite.cs
index d8c4904c..87183067 100644
--- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessWrite.cs
+++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessWrite.cs
@@ -34,8 +34,8 @@ namespace Renci.SshNet.Tests.Classes.Sftp
_readBufferSize = (uint) _random.Next(5, 1000);
_writeBufferSize = (uint) _random.Next(5, 1000);
_handle = GenerateRandom(_random.Next(1, 10), _random);
- _fileAttributes = new SftpFileAttributesBuilder().WithLastAccessTime(DateTime.Now.AddSeconds(_random.Next()))
- .WithLastWriteTime(DateTime.Now.AddSeconds(_random.Next()))
+ _fileAttributes = new SftpFileAttributesBuilder().WithLastAccessTime(DateTime.UtcNow.AddSeconds(_random.Next()))
+ .WithLastWriteTime(DateTime.UtcNow.AddSeconds(_random.Next()))
.WithSize(_random.Next())
.WithUserId(_random.Next())
.WithGroupId(_random.Next())
diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthGreatherThanPosition.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthGreatherThanPosition.cs
index aee4b276..59a0135f 100644
--- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthGreatherThanPosition.cs
+++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthGreatherThanPosition.cs
@@ -53,8 +53,8 @@ namespace Renci.SshNet.Tests.Classes.Sftp
_fileAttributes = new SftpFileAttributesBuilder().WithExtension("X", "ABC")
.WithExtension("V", "VValue")
.WithGroupId(random.Next())
- .WithLastAccessTime(DateTime.Now.AddSeconds(random.Next()))
- .WithLastWriteTime(DateTime.Now.AddSeconds(random.Next()))
+ .WithLastAccessTime(DateTime.UtcNow.AddSeconds(random.Next()))
+ .WithLastWriteTime(DateTime.UtcNow.AddSeconds(random.Next()))
.WithPermissions((uint) random.Next())
.WithSize(_length + 100)
.WithUserId(random.Next())
@@ -201,4 +201,4 @@ namespace Renci.SshNet.Tests.Classes.Sftp
SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(4));
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthLessThanPosition.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthLessThanPosition.cs
index ae3952cc..a6116339 100644
--- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthLessThanPosition.cs
+++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthLessThanPosition.cs
@@ -50,8 +50,8 @@ namespace Renci.SshNet.Tests.Classes.Sftp
_fileAttributes = new SftpFileAttributesBuilder().WithExtension("X", "ABC")
.WithExtension("V", "VValue")
.WithGroupId(random.Next())
- .WithLastAccessTime(DateTime.Now.AddSeconds(random.Next()))
- .WithLastWriteTime(DateTime.Now.AddSeconds(random.Next()))
+ .WithLastAccessTime(DateTime.UtcNow.AddSeconds(random.Next()))
+ .WithLastWriteTime(DateTime.UtcNow.AddSeconds(random.Next()))
.WithPermissions((uint)random.Next())
.WithSize(_length + 100)
.WithUserId(random.Next())
diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthGreatherThanPosition.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthGreatherThanPosition.cs
index 5a19aa3e..c71b43c8 100644
--- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthGreatherThanPosition.cs
+++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthGreatherThanPosition.cs
@@ -54,8 +54,8 @@ namespace Renci.SshNet.Tests.Classes.Sftp
_fileAttributes = new SftpFileAttributesBuilder().WithExtension("X", "ABC")
.WithExtension("V", "VValue")
.WithGroupId(random.Next())
- .WithLastAccessTime(DateTime.Now.AddSeconds(random.Next()))
- .WithLastWriteTime(DateTime.Now.AddSeconds(random.Next()))
+ .WithLastAccessTime(DateTime.UtcNow.AddSeconds(random.Next()))
+ .WithLastWriteTime(DateTime.UtcNow.AddSeconds(random.Next()))
.WithPermissions((uint)random.Next())
.WithSize(_length + 100)
.WithUserId(random.Next())
diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthLessThanPosition.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthLessThanPosition.cs
index cfcf2315..96ad14b1 100644
--- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthLessThanPosition.cs
+++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthLessThanPosition.cs
@@ -54,8 +54,8 @@ namespace Renci.SshNet.Tests.Classes.Sftp
_fileAttributes = new SftpFileAttributesBuilder().WithExtension("X", "ABC")
.WithExtension("V", "VValue")
.WithGroupId(random.Next())
- .WithLastAccessTime(DateTime.Now.AddSeconds(random.Next()))
- .WithLastWriteTime(DateTime.Now.AddSeconds(random.Next()))
+ .WithLastAccessTime(DateTime.UtcNow.AddSeconds(random.Next()))
+ .WithLastWriteTime(DateTime.UtcNow.AddSeconds(random.Next()))
.WithPermissions((uint) random.Next())
.WithSize(_length + 100)
.WithUserId(random.Next())
diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessReadWrite.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessReadWrite.cs
index 0fde319a..ef89483b 100644
--- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessReadWrite.cs
+++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessReadWrite.cs
@@ -48,8 +48,8 @@ namespace Renci.SshNet.Tests.Classes.Sftp
_writeBufferSize = (uint) random.Next(0, 1000);
_length = random.Next();
- _fileAttributesLastAccessTime = DateTime.Now.AddSeconds(random.Next());
- _fileAttributesLastWriteTime = DateTime.Now.AddSeconds(random.Next());
+ _fileAttributesLastAccessTime = DateTime.UtcNow.AddSeconds(random.Next());
+ _fileAttributesLastWriteTime = DateTime.UtcNow.AddSeconds(random.Next());
_fileAttributesSize = random.Next();
_fileAttributesUserId = random.Next();
_fileAttributesGroupId = random.Next();
diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessWrite.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessWrite.cs
index ce2619a5..73b5a953 100644
--- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessWrite.cs
+++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessWrite.cs
@@ -48,8 +48,8 @@ namespace Renci.SshNet.Tests.Classes.Sftp
_writeBufferSize = (uint) random.Next(0, 1000);
_length = random.Next();
- _fileAttributesLastAccessTime = DateTime.Now.AddSeconds(random.Next());
- _fileAttributesLastWriteTime = DateTime.Now.AddSeconds(random.Next());
+ _fileAttributesLastAccessTime = DateTime.UtcNow.AddSeconds(random.Next());
+ _fileAttributesLastWriteTime = DateTime.UtcNow.AddSeconds(random.Next());
_fileAttributesSize = random.Next();
_fileAttributesUserId = random.Next();
_fileAttributesGroupId = random.Next();
diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Write_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Write_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs
index 68020d55..e7d53706 100644
--- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Write_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs
+++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Write_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs
@@ -119,8 +119,8 @@ namespace Renci.SshNet.Tests.Classes.Sftp
[TestMethod]
public void LengthShouldFlushBufferAndReturnSizeOfFile()
{
- var lengthFileAttributes = new SftpFileAttributes(DateTime.Now,
- DateTime.Now,
+ var lengthFileAttributes = new SftpFileAttributes(DateTime.UtcNow,
+ DateTime.UtcNow,
_random.Next(),
_random.Next(),
_random.Next(),
diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs
index 3edd7c7b..f562f66b 100644
--- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs
+++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs
@@ -1076,7 +1076,9 @@ namespace Renci.SshNet.Tests.Classes
SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value
string path = string.Empty; // TODO: Initialize to an appropriate value
DateTime lastAccessTime = new DateTime(); // TODO: Initialize to an appropriate value
+#pragma warning disable CS0618 // Type or member is obsolete
target.SetLastAccessTime(path, lastAccessTime);
+#pragma warning restore CS0618 // Type or member is obsolete
Assert.Inconclusive("A method that does not return a value cannot be verified.");
}
@@ -1091,7 +1093,9 @@ namespace Renci.SshNet.Tests.Classes
SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value
string path = string.Empty; // TODO: Initialize to an appropriate value
DateTime lastAccessTimeUtc = new DateTime(); // TODO: Initialize to an appropriate value
+#pragma warning disable CS0618 // Type or member is obsolete
target.SetLastAccessTimeUtc(path, lastAccessTimeUtc);
+#pragma warning restore CS0618 // Type or member is obsolete
Assert.Inconclusive("A method that does not return a value cannot be verified.");
}
@@ -1106,7 +1110,9 @@ namespace Renci.SshNet.Tests.Classes
SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value
string path = string.Empty; // TODO: Initialize to an appropriate value
DateTime lastWriteTime = new DateTime(); // TODO: Initialize to an appropriate value
+#pragma warning disable CS0618 // Type or member is obsolete
target.SetLastWriteTime(path, lastWriteTime);
+#pragma warning restore CS0618 // Type or member is obsolete
Assert.Inconclusive("A method that does not return a value cannot be verified.");
}
@@ -1121,7 +1127,9 @@ namespace Renci.SshNet.Tests.Classes
SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value
string path = string.Empty; // TODO: Initialize to an appropriate value
DateTime lastWriteTimeUtc = new DateTime(); // TODO: Initialize to an appropriate value
+#pragma warning disable CS0618 // Type or member is obsolete
target.SetLastWriteTimeUtc(path, lastWriteTimeUtc);
+#pragma warning restore CS0618 // Type or member is obsolete
Assert.Inconclusive("A method that does not return a value cannot be verified.");
}
@@ -1403,4 +1411,4 @@ namespace Renci.SshNet.Tests.Classes
public SftpDownloadAsyncResult DownloadResult { get; set; }
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTestBase.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTestBase.cs
new file mode 100644
index 00000000..11657962
--- /dev/null
+++ b/src/Renci.SshNet.Tests/Classes/SftpClientTestBase.cs
@@ -0,0 +1,19 @@
+using Moq;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes
+{
+ public abstract class SftpClientTestBase : BaseClientTestBase
+ {
+ internal Mock _sftpResponseFactoryMock { get; private set; }
+ internal Mock _sftpSessionMock { get; private set; }
+
+ protected override void CreateMocks()
+ {
+ base.CreateMocks();
+
+ _sftpResponseFactoryMock = new Mock(MockBehavior.Strict);
+ _sftpSessionMock = new Mock(MockBehavior.Strict);
+ }
+ }
+}
diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs
index afbc247b..b3bcb8e8 100644
--- a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs
+++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs
@@ -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 _serviceFactoryMock;
- private Mock _sessionMock;
- private Mock _sftpResponseFactoryMock;
- private Mock _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(MockBehavior.Strict);
- _sessionMock = new Mock(MockBehavior.Strict);
- _sftpResponseFactoryMock = new Mock(MockBehavior.Strict);
- _sftpSessionMock = new Mock(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
{
diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Connected.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Connected.cs
index ba7d080f..239c8493 100644
--- a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Connected.cs
+++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Connected.cs
@@ -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 _serviceFactoryMock;
- private Mock _sessionMock;
- private Mock _sftpResponseFactoryMock;
- private Mock _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(MockBehavior.Strict);
- _sessionMock = new Mock(MockBehavior.Strict);
- _sftpResponseFactoryMock = new Mock(MockBehavior.Strict);
- _sftpSessionMock = new Mock(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]
diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disconnected.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disconnected.cs
index 516b8aeb..192c5e95 100644
--- a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disconnected.cs
+++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disconnected.cs
@@ -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 _serviceFactoryMock;
- private Mock _sessionMock;
- private Mock _sftpResponseFactoryMock;
- private Mock _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(MockBehavior.Strict);
- _sessionMock = new Mock(MockBehavior.Strict);
- _sftpResponseFactoryMock = new Mock(MockBehavior.Strict);
- _sftpSessionMock = new Mock(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]
diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disposed.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disposed.cs
index 73b07ad4..11e00ad0 100644
--- a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disposed.cs
+++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disposed.cs
@@ -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 _serviceFactoryMock;
- private Mock _sessionMock;
- private Mock _sftpResponseFactoryMock;
- private Mock _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(MockBehavior.Strict);
- _sessionMock = new Mock(MockBehavior.Strict);
- _sftpResponseFactoryMock = new Mock