From b2be9dd007dae7dfe26aeb6c067cec9463fa4e1a Mon Sep 17 00:00:00 2001 From: Robert Hague Date: Fri, 9 Aug 2024 18:31:13 +0200 Subject: [PATCH] Port shared tests folder These tests were presumably once shared with the old integration tests repo but have since been sat doing nothing. This brings them into the unit tests project. --- .../Abstractions/SocketAbstraction.cs | 4 +- .../Abstractions/ThreadAbstraction.cs | 9 - src/Renci.SshNet/SshMessageFactory.cs | 4 +- .../CryptoAbstraction_GenerateRandom.cs | 49 - .../DnsAbstraction_GetHostAddresses.cs | 84 -- .../FileSystemAbstraction_EnumerateFiles.cs | 162 --- .../SocketAbstraction_CanWrite.cs | 20 - .../ThreadAbstraction_ExecuteThread.cs | 61 -- .../Renci.SshNet.Shared.Tests.projitems | 23 - .../Renci.SshNet.Shared.Tests.shproj | 13 - .../SshMessageFactoryTest.cs | 982 ------------------ .../Classes/AbstractionsTest.cs | 63 ++ .../ForwardedPortStatusTest_Started.cs | 6 +- .../ForwardedPortStatusTest_Starting.cs | 6 +- .../ForwardedPortStatusTest_Stopped.cs | 6 +- .../ForwardedPortStatusTest_Stopping.cs | 4 +- .../Classes/SshMessageFactoryTest.cs | 423 ++++++++ .../Common/HttpProxyStub.cs | 179 ---- test/Renci.SshNet.Tests/Common/HttpRequest.cs | 17 - 19 files changed, 502 insertions(+), 1613 deletions(-) delete mode 100644 test/Renci.SshNet.Shared.Tests/Abstractions/CryptoAbstraction_GenerateRandom.cs delete mode 100644 test/Renci.SshNet.Shared.Tests/Abstractions/DnsAbstraction_GetHostAddresses.cs delete mode 100644 test/Renci.SshNet.Shared.Tests/Abstractions/FileSystemAbstraction_EnumerateFiles.cs delete mode 100644 test/Renci.SshNet.Shared.Tests/Abstractions/SocketAbstraction_CanWrite.cs delete mode 100644 test/Renci.SshNet.Shared.Tests/Abstractions/ThreadAbstraction_ExecuteThread.cs delete mode 100644 test/Renci.SshNet.Shared.Tests/Renci.SshNet.Shared.Tests.projitems delete mode 100644 test/Renci.SshNet.Shared.Tests/Renci.SshNet.Shared.Tests.shproj delete mode 100644 test/Renci.SshNet.Shared.Tests/SshMessageFactoryTest.cs create mode 100644 test/Renci.SshNet.Tests/Classes/AbstractionsTest.cs rename test/{Renci.SshNet.Shared.Tests => Renci.SshNet.Tests/Classes}/ForwardedPortStatusTest_Started.cs (97%) rename test/{Renci.SshNet.Shared.Tests => Renci.SshNet.Tests/Classes}/ForwardedPortStatusTest_Starting.cs (97%) rename test/{Renci.SshNet.Shared.Tests => Renci.SshNet.Tests/Classes}/ForwardedPortStatusTest_Stopped.cs (97%) rename test/{Renci.SshNet.Shared.Tests => Renci.SshNet.Tests/Classes}/ForwardedPortStatusTest_Stopping.cs (98%) create mode 100644 test/Renci.SshNet.Tests/Classes/SshMessageFactoryTest.cs delete mode 100644 test/Renci.SshNet.Tests/Common/HttpProxyStub.cs delete mode 100644 test/Renci.SshNet.Tests/Common/HttpRequest.cs diff --git a/src/Renci.SshNet/Abstractions/SocketAbstraction.cs b/src/Renci.SshNet/Abstractions/SocketAbstraction.cs index da1018cd0..f6ce8a4c5 100644 --- a/src/Renci.SshNet/Abstractions/SocketAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/SocketAbstraction.cs @@ -292,7 +292,7 @@ public static int Read(Socket socket, byte[] buffer, int offset, int size, TimeS { if (IsErrorResumable(ex.SocketErrorCode)) { - ThreadAbstraction.Sleep(30); + Thread.Sleep(30); continue; } @@ -346,7 +346,7 @@ public static void Send(Socket socket, byte[] data, int offset, int size) if (IsErrorResumable(ex.SocketErrorCode)) { // socket buffer is probably full, wait and try again - ThreadAbstraction.Sleep(30); + Thread.Sleep(30); } else { diff --git a/src/Renci.SshNet/Abstractions/ThreadAbstraction.cs b/src/Renci.SshNet/Abstractions/ThreadAbstraction.cs index b3fe2bb4f..a74389a38 100644 --- a/src/Renci.SshNet/Abstractions/ThreadAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/ThreadAbstraction.cs @@ -6,15 +6,6 @@ namespace Renci.SshNet.Abstractions { internal static class ThreadAbstraction { - /// - /// Suspends the current thread for the specified number of milliseconds. - /// - /// The number of milliseconds for which the thread is suspended. - public static void Sleep(int millisecondsTimeout) - { - Thread.Sleep(millisecondsTimeout); - } - /// /// Creates and starts a long-running for the specified . /// diff --git a/src/Renci.SshNet/SshMessageFactory.cs b/src/Renci.SshNet/SshMessageFactory.cs index 2887559a6..630ebaad2 100644 --- a/src/Renci.SshNet/SshMessageFactory.cs +++ b/src/Renci.SshNet/SshMessageFactory.cs @@ -16,7 +16,7 @@ internal sealed class SshMessageFactory private readonly bool[] _activatedMessagesById; private readonly object _lock = new object(); - private static readonly MessageMetadata[] AllMessages = new MessageMetadata[] + internal static readonly MessageMetadata[] AllMessages = new MessageMetadata[] { new MessageMetadata(0, "SSH_MSG_KEXINIT", 20), new MessageMetadata(1, "SSH_MSG_NEWKEYS", 21), @@ -263,7 +263,7 @@ private static SshException CreateMessageTypeAlreadyEnabledForOtherMessageExcept currentEnabledForMessageName)); } - private abstract class MessageMetadata + internal abstract class MessageMetadata { protected MessageMetadata(byte id, string name, byte number) { diff --git a/test/Renci.SshNet.Shared.Tests/Abstractions/CryptoAbstraction_GenerateRandom.cs b/test/Renci.SshNet.Shared.Tests/Abstractions/CryptoAbstraction_GenerateRandom.cs deleted file mode 100644 index aa4bbce37..000000000 --- a/test/Renci.SshNet.Shared.Tests/Abstractions/CryptoAbstraction_GenerateRandom.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Linq; -using Renci.SshNet.Abstractions; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Renci.SshNet.Tests.Abstractions -{ - [TestClass] - public class CryptoAbstraction_GenerateRandom - { - [TestMethod] - public void ShouldThrowArgumentNullExceptionWhenDataIsNull() - { - const byte[] data = null; - - try - { - CryptoAbstraction.GenerateRandom(data); - Assert.Fail(); - } - catch (ArgumentNullException ex) - { - Assert.IsNull(ex.InnerException); - Assert.AreEqual("data", ex.ParamName); - } - } - - [TestMethod] - public void ShouldPerformNoOpWhenDataIsZeroLength() - { - var data = new byte[0]; - - CryptoAbstraction.GenerateRandom(data); - } - - [TestMethod] - public void ShouldGenerateRandomSequenceOfValues() - { - var dataLength = new Random().Next(1, 100); - var dataA = new byte[dataLength]; - var dataB = new byte[dataLength]; - - CryptoAbstraction.GenerateRandom(dataA); - CryptoAbstraction.GenerateRandom(dataB); - - Assert.IsFalse(dataA.SequenceEqual(dataB)); - } - } -} diff --git a/test/Renci.SshNet.Shared.Tests/Abstractions/DnsAbstraction_GetHostAddresses.cs b/test/Renci.SshNet.Shared.Tests/Abstractions/DnsAbstraction_GetHostAddresses.cs deleted file mode 100644 index 556164bef..000000000 --- a/test/Renci.SshNet.Shared.Tests/Abstractions/DnsAbstraction_GetHostAddresses.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Net; -using System.Net.Sockets; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Abstractions; - -namespace Renci.SshNet.Tests.Abstractions -{ - [TestClass] - public class DnsAbstraction_GetHostAddresses - { - [TestMethod] - public void ShouldThrowArgumentNullExceptionWhenHostNameOrAddressIsNull() - { - const string hostNameOrAddress = null; - - try - { - DnsAbstraction.GetHostAddresses(hostNameOrAddress); - Assert.Fail(); - } - catch (ArgumentNullException) - { - } - } - - [TestMethod] - public void ShouldThrowSocketExceptionWhenHostIsNotFound() - { - const string hostNameOrAddress = "surelydoesnotexist.OrAmIWrong"; - - try - { - var addresses = DnsAbstraction.GetHostAddresses(hostNameOrAddress); - Assert.Fail(addresses.ToString()); - } - catch (SocketException ex) - { - Assert.IsNull(ex.InnerException); - Assert.AreEqual(SocketError.HostNotFound, ex.SocketErrorCode); - } - } - - [TestMethod] - public void ShouldReturnHostAddressesOfLocalHostWhenHostNameOrAddressIsEmpty() - { - const string hostNameOrAddress = ""; - - var addresses = DnsAbstraction.GetHostAddresses(hostNameOrAddress); - Assert.IsNotNull(addresses); - - var hostEntry = Dns.GetHostEntry(Dns.GetHostName()); - Assert.IsNotNull(hostEntry); - - Assert.AreEqual(hostEntry.AddressList.Length, addresses.Length); - for (var i = 0; i < hostEntry.AddressList.Length; i++) - Assert.AreEqual(hostEntry.AddressList[i], addresses[i]); - } - - [TestMethod] - public void ShouldReturnSingleIpv4AddressWhenHostNameOrAddressIsValidIpv4Address() - { - const string hostNameOrAddress = "1.2.3.4"; - - var addresses = DnsAbstraction.GetHostAddresses(hostNameOrAddress); - Assert.IsNotNull(addresses); - Assert.AreEqual(1, addresses.Length); - Assert.AreEqual(AddressFamily.InterNetwork, addresses[0].AddressFamily); - Assert.AreEqual(IPAddress.Parse(hostNameOrAddress), addresses[0]); - } - - [TestMethod] - public void ShouldReturnSingleIpv6AddressWhenHostNameOrAddressIsValidIpv6Address() - { - const string hostNameOrAddress = "2001:0:9d38:90d7:384f:2133:ab3d:d152"; - - var addresses = DnsAbstraction.GetHostAddresses(hostNameOrAddress); - Assert.IsNotNull(addresses); - Assert.AreEqual(1, addresses.Length); - Assert.AreEqual(AddressFamily.InterNetworkV6, addresses[0].AddressFamily); - Assert.AreEqual(IPAddress.Parse(hostNameOrAddress), addresses[0]); - } - } -} diff --git a/test/Renci.SshNet.Shared.Tests/Abstractions/FileSystemAbstraction_EnumerateFiles.cs b/test/Renci.SshNet.Shared.Tests/Abstractions/FileSystemAbstraction_EnumerateFiles.cs deleted file mode 100644 index d73e4cae6..000000000 --- a/test/Renci.SshNet.Shared.Tests/Abstractions/FileSystemAbstraction_EnumerateFiles.cs +++ /dev/null @@ -1,162 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using Renci.SshNet.Abstractions; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Renci.SshNet.Tests.Abstractions -{ - [TestClass] - public class FileSystemAbstraction_EnumerateFiles - { - private string _temporaryDirectory; - - [TestInitialize] - public void SetUp() - { - _temporaryDirectory = Path.GetTempFileName(); - File.Delete(_temporaryDirectory); - Directory.CreateDirectory(_temporaryDirectory); - } - - [TestCleanup] - public void TearDown() - { - if (_temporaryDirectory != null && Directory.Exists(_temporaryDirectory)) - { - Directory.Delete(_temporaryDirectory, true); - } - } - - [TestMethod] - public void ShouldThrowArgumentNullExceptionWhenDirectoryInfoIsNull() - { - const DirectoryInfo directoryInfo = null; - const string searchPattern = "*.xml"; - - try - { - FileSystemAbstraction.EnumerateFiles(directoryInfo, searchPattern); - Assert.Fail(); - } - catch (ArgumentNullException ex) - { - Assert.IsNull(ex.InnerException); - Assert.AreEqual("directoryInfo", ex.ParamName); - } - } - - [TestMethod] - public void ShouldThrowArgumentNullExceptionWhenSearchPatternIsNull() - { - var directoryInfo = new DirectoryInfo(_temporaryDirectory); - const string searchPattern = null; - - try - { - FileSystemAbstraction.EnumerateFiles(directoryInfo, searchPattern); - Assert.Fail(); - } - catch (ArgumentNullException ex) - { - Assert.IsNull(ex.InnerException); - Assert.AreEqual("searchPattern", ex.ParamName); - } - } - - [TestMethod] - public void ShouldThrowDirectoryNotFoundExceptionWhenDirectoryDoesNotExist() - { - var directoryInfo = new DirectoryInfo(_temporaryDirectory); - const string searchPattern = "*.xml"; - - Directory.Delete(_temporaryDirectory, true); - - try - { - FileSystemAbstraction.EnumerateFiles(directoryInfo, searchPattern); - Assert.Fail(); - } - catch (DirectoryNotFoundException) - { - } - } - - [TestMethod] - public void ShouldReturnEmptyEnumerableWhenNoFilesExistInDirectory() - { - var directoryInfo = new DirectoryInfo(_temporaryDirectory); - const string searchPattern = "*.xml"; - - var actual = FileSystemAbstraction.EnumerateFiles(directoryInfo, searchPattern); - - Assert.IsFalse(actual.GetEnumerator().MoveNext()); - } - - [TestMethod] - public void ShouldReturnEmptyEnumerableWhenNoFilesMatchSearchPatternExistInDirectory() - { - CreateFile(Path.Combine(_temporaryDirectory, "test.txt")); - - var directoryInfo = new DirectoryInfo(_temporaryDirectory); - const string searchPattern = "*.xml"; - - var actual = FileSystemAbstraction.EnumerateFiles(directoryInfo, searchPattern); - - Assert.IsFalse(actual.GetEnumerator().MoveNext()); - } - - [TestMethod] - public void ShouldReturnEmptyEnumerableWhenSearchPatternIsEmpty() - { - CreateFile(Path.Combine(_temporaryDirectory, "test.txt")); - - var directoryInfo = new DirectoryInfo(_temporaryDirectory); - const string searchPattern = ""; - - var actual = FileSystemAbstraction.EnumerateFiles(directoryInfo, searchPattern); - - Assert.IsFalse(actual.GetEnumerator().MoveNext()); - } - - [TestMethod] - public void ShouldReturnAllFilesInDirectoryWhenSearchPatternIsAsterisk() - { - CreateFile(Path.Combine(_temporaryDirectory, "test.txt")); - CreateFile(Path.Combine(_temporaryDirectory, "test.xml")); - - var directoryInfo = new DirectoryInfo(_temporaryDirectory); - const string searchPattern = "*"; - - var actual = FileSystemAbstraction.EnumerateFiles(directoryInfo, searchPattern).ToList(); - - Assert.AreEqual(2, actual.Count); - Assert.IsTrue(actual.Exists(p => p.Name == "test.txt")); - Assert.IsTrue(actual.Exists(p => p.Name == "test.xml")); - } - - [TestMethod] - public void ShouldReturnOnlyReturnFilesFromTopLevelDirectory() - { - CreateFile(Path.Combine(_temporaryDirectory, "test.txt")); - CreateFile(Path.Combine(_temporaryDirectory, "test.xml")); - Directory.CreateDirectory(Path.Combine(_temporaryDirectory, "sub")); - CreateFile(Path.Combine(_temporaryDirectory, "sub", "test.csv")); - - var directoryInfo = new DirectoryInfo(_temporaryDirectory); - const string searchPattern = "*"; - - var actual = FileSystemAbstraction.EnumerateFiles(directoryInfo, searchPattern).ToList(); - - Assert.AreEqual(2, actual.Count); - Assert.IsTrue(actual.Exists(p => p.Name == "test.txt")); - Assert.IsTrue(actual.Exists(p => p.Name == "test.xml")); - } - - private static void CreateFile(string fileName) - { - var fs = File.Create(fileName); - fs.Dispose(); - } - } -} diff --git a/test/Renci.SshNet.Shared.Tests/Abstractions/SocketAbstraction_CanWrite.cs b/test/Renci.SshNet.Shared.Tests/Abstractions/SocketAbstraction_CanWrite.cs deleted file mode 100644 index 014b5f6fe..000000000 --- a/test/Renci.SshNet.Shared.Tests/Abstractions/SocketAbstraction_CanWrite.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Net.Sockets; -using Renci.SshNet.Abstractions; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Renci.SshNet.Tests.Abstractions -{ - [TestClass] - public class SocketAbstraction_CanWrite - { - [TestMethod] - public void ShouldReturnFalseWhenSocketIsNull() - { - const Socket socket = null; - - var actual = SocketAbstraction.CanWrite(socket); - - Assert.IsFalse(actual); - } - } -} diff --git a/test/Renci.SshNet.Shared.Tests/Abstractions/ThreadAbstraction_ExecuteThread.cs b/test/Renci.SshNet.Shared.Tests/Abstractions/ThreadAbstraction_ExecuteThread.cs deleted file mode 100644 index 74a1cca22..000000000 --- a/test/Renci.SshNet.Shared.Tests/Abstractions/ThreadAbstraction_ExecuteThread.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Threading; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Abstractions; - -namespace Renci.SshNet.Tests.Abstractions -{ - [TestClass] - public class ThreadAbstraction_ExecuteThread - { - [TestMethod] - public void ShouldThrowArgumentNullExceptionWhenActionIsNull() - { - const Action action = null; - - try - { - ThreadAbstraction.ExecuteThread(action); - Assert.Fail(); - } - catch (ArgumentNullException ex) - { - Assert.IsNull(ex.InnerException); - Assert.AreEqual("action", ex.ParamName); - } - } - - [TestMethod] - public void ShouldExecuteActionOnSeparateThread() - { - DateTime? executionTime = null; - int executionCount = 0; - EventWaitHandle waitHandle = new ManualResetEvent(false); - - Action action = () => - { - ThreadAbstraction.Sleep(500); - executionCount++; - executionTime = DateTime.Now; - waitHandle.Set(); - }; - - DateTime start = DateTime.Now; - - ThreadAbstraction.ExecuteThread(action); - - Assert.AreEqual(0, executionCount); - Assert.IsNull(executionTime); - - Assert.IsTrue(waitHandle.WaitOne(2000)); - - Assert.AreEqual(1, executionCount); - Assert.IsNotNull(executionTime); - - var elapsedTime = executionTime.Value - start; - Assert.IsTrue(elapsedTime > TimeSpan.Zero); - Assert.IsTrue(elapsedTime > TimeSpan.FromMilliseconds(500)); - Assert.IsTrue(elapsedTime < TimeSpan.FromMilliseconds(1000)); - } - } -} diff --git a/test/Renci.SshNet.Shared.Tests/Renci.SshNet.Shared.Tests.projitems b/test/Renci.SshNet.Shared.Tests/Renci.SshNet.Shared.Tests.projitems deleted file mode 100644 index 7539d3849..000000000 --- a/test/Renci.SshNet.Shared.Tests/Renci.SshNet.Shared.Tests.projitems +++ /dev/null @@ -1,23 +0,0 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - true - fae3948f-a438-458e-8e0e-7f6e39a5dd8a - - - Renci.SshNet.Tests - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/Renci.SshNet.Shared.Tests/Renci.SshNet.Shared.Tests.shproj b/test/Renci.SshNet.Shared.Tests/Renci.SshNet.Shared.Tests.shproj deleted file mode 100644 index 72088027e..000000000 --- a/test/Renci.SshNet.Shared.Tests/Renci.SshNet.Shared.Tests.shproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - fae3948f-a438-458e-8e0e-7f6e39a5dd8a - 14.0 - - - - - - - - diff --git a/test/Renci.SshNet.Shared.Tests/SshMessageFactoryTest.cs b/test/Renci.SshNet.Shared.Tests/SshMessageFactoryTest.cs deleted file mode 100644 index a66cdf873..000000000 --- a/test/Renci.SshNet.Shared.Tests/SshMessageFactoryTest.cs +++ /dev/null @@ -1,982 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.Linq; -using Renci.SshNet.Common; -using Renci.SshNet.Messages; -using Renci.SshNet.Messages.Authentication; -using Renci.SshNet.Messages.Connection; -using Renci.SshNet.Messages.Transport; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Renci.SshNet.Tests -{ - [TestClass] - public class SshMessageFactoryTest - { - private SshMessageFactory _sshMessageFactory; - private SshMessageFactoryOriginal _sshMessageFactoryOriginal; - - [TestInitialize] - public void SetUp() - { - _sshMessageFactory = new SshMessageFactory(); - _sshMessageFactoryOriginal = new SshMessageFactoryOriginal(); - } - - [TestMethod] - public void CreateShouldThrowSshExceptionWhenMessageIsNotEnabled() - { - const byte messageNumber = 60; - - try - { - _sshMessageFactory.Create(messageNumber); - Assert.Fail(); - } - catch (SshException ex) - { - Assert.IsNull(ex.InnerException); - Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message); - } - } - - [TestMethod] - public void CreateShouldThrowSshExceptionWhenMessageDoesNotExist_OutsideOfMessageNumberRange() - { - const byte messageNumber = 255; - - try - { - _sshMessageFactory.Create(messageNumber); - Assert.Fail(); - } - catch (SshException ex) - { - Assert.IsNull(ex.InnerException); - Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not supported.", messageNumber), ex.Message); - } - } - - [TestMethod] - public void CreateShouldThrowSshExceptionWhenMessageDoesNotExist_WithinMessageNumberRange() - { - const byte messageNumber = 5; - - try - { - _sshMessageFactory.Create(messageNumber); - Assert.Fail(); - } - catch (SshException ex) - { - Assert.IsNull(ex.InnerException); - Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not supported.", messageNumber), ex.Message); - } - } - - [TestMethod] - public void CreateShouldThrowSshExceptionWhenMessageIsNotActivated() - { - const byte messageNumber = 60; - const string messageName = "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"; - - _sshMessageFactory.EnableAndActivateMessage(messageName); - _sshMessageFactory.DisableAndDeactivateMessage(messageName); - - try - { - _sshMessageFactory.Create(messageNumber); - Assert.Fail(); - } - catch (SshException ex) - { - Assert.IsNull(ex.InnerException); - Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message); - } - } - - [TestMethod] - public void CreateShouldReturnMessageInstanceCorrespondingToMessageNumberWhenMessageIsEnabledAndActivated() - { - const byte messageNumber = 60; - const string messageName = "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"; - - _sshMessageFactory.EnableAndActivateMessage(messageName); - - var actual = _sshMessageFactory.Create(messageNumber); - - Assert.IsNotNull(actual); - Assert.AreEqual(typeof (PasswordChangeRequiredMessage), actual.GetType()); - - _sshMessageFactory.DisableAndDeactivateMessage(messageName); - _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST"); - - actual = _sshMessageFactory.Create(messageNumber); - - Assert.IsNotNull(actual); - Assert.AreEqual(typeof(InformationRequestMessage), actual.GetType()); - } - - [TestMethod] - public void DisableAndDeactivateMessageShouldThrowSshExceptionWhenAnotherMessageWithSameMessageNumberIsEnabled() - { - _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); - - try - { - _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST"); - Assert.Fail(); - } - catch (SshException ex) - { - Assert.IsNull(ex.InnerException); - Assert.AreEqual("Cannot enable message 'SSH_MSG_USERAUTH_INFO_REQUEST'. Message type 60 is already enabled for 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ'.", ex.Message); - } - - // verify that the original message remains enabled - var actual = _sshMessageFactory.Create(60); - Assert.IsNotNull(actual); - Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType()); - } - - [TestMethod] - public void DisableAndDeactivateMessageShouldNotThrowExceptionWhenMessageIsAlreadyDisabled() - { - const byte messageNumber = 60; - - _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); - _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); - _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); - - // verify that message remains disabled - try - { - _sshMessageFactory.Create(messageNumber); - Assert.Fail(); - } - catch (SshException ex) - { - Assert.IsNull(ex.InnerException); - Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message); - } - } - - [TestMethod] - public void DisableAndDeactivateMessageShouldNotThrowExceptionWhenMessageWasNeverEnabled() - { - const byte messageNumber = 60; - - _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); - - // verify that message is disabled - try - { - _sshMessageFactory.Create(messageNumber); - Assert.Fail(); - } - catch (SshException ex) - { - Assert.IsNull(ex.InnerException); - Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message); - } - } - - [TestMethod] - public void DisableAndDeactivateMessageShouldThrowSshExceptionWhenMessageIsNotSupported() - { - const string messageName = "WHATEVER"; - - try - { - _sshMessageFactory.DisableAndDeactivateMessage("WHATEVER"); - Assert.Fail(); - } - catch (SshException ex) - { - Assert.IsNull(ex.InnerException); - Assert.AreEqual(string.Format("Message '{0}' is not supported.", messageName), ex.Message); - } - } - - [TestMethod] - public void DisableAndDeactivateMessageShouldThrowArgumentNullExceptionWhenMessageNameIsNull() - { - const string messageName = null; - - try - { - _sshMessageFactory.DisableAndDeactivateMessage(messageName); - Assert.Fail(); - } - catch (ArgumentNullException ex) - { - Assert.IsNull(ex.InnerException); - Assert.AreEqual("messageName", ex.ParamName); - } - } - - [TestMethod] - public void EnableAndActivateMessageShouldThrowSshExceptionWhenAnotherMessageWithSameMessageNumberIsAlreadyEnabled() - { - _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); - - try - { - _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST"); - Assert.Fail(); - } - catch (SshException ex) - { - Assert.IsNull(ex.InnerException); - Assert.AreEqual("Cannot enable message 'SSH_MSG_USERAUTH_INFO_REQUEST'. Message type 60 is already enabled for 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ'.", ex.Message); - } - - // verify that the original message remains enabled - var actual = _sshMessageFactory.Create(60); - Assert.IsNotNull(actual); - Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType()); - } - - [TestMethod] - public void EnableAndActivateMessageShouldNotThrowExceptionWhenMessageIsAlreadyEnabled() - { - _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); - _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); - - var actual = _sshMessageFactory.Create(60); - Assert.IsNotNull(actual); - Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType()); - } - - [TestMethod] - public void EnableAndActivateMessageShouldThrowSshExceptionWhenMessageIsNotSupported() - { - const string messageName = "WHATEVER"; - - try - { - _sshMessageFactory.EnableAndActivateMessage("WHATEVER"); - Assert.Fail(); - } - catch (SshException ex) - { - Assert.IsNull(ex.InnerException); - Assert.AreEqual(string.Format("Message '{0}' is not supported.", messageName), ex.Message); - } - } - - [TestMethod] - public void EnableAndActivateMessageShouldThrowArgumentNullExceptionWhenMessageNameIsNull() - { - const string messageName = null; - - try - { - _sshMessageFactory.EnableAndActivateMessage(messageName); - Assert.Fail(); - } - catch (ArgumentNullException ex) - { - Assert.IsNull(ex.InnerException); - Assert.AreEqual("messageName", ex.ParamName); - } - } - - [TestMethod] - public void DisableNonKeyExchangeMessagesShouldDisableNonKeyExchangeMessages() - { - const byte messageNumber = 60; - - _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); - _sshMessageFactory.DisableNonKeyExchangeMessages(); - - // verify that message is disabled - try - { - _sshMessageFactory.Create(messageNumber); - Assert.Fail(); - } - catch (SshException ex) - { - Assert.IsNull(ex.InnerException); - Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message); - } - } - - [TestMethod] - public void DisableNonKeyExchangeMessagesShouldNotDisableKeyExchangeMessages() - { - const byte messageNumber = 21; - - _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_NEWKEYS"); - _sshMessageFactory.DisableNonKeyExchangeMessages(); - - // verify that message remains enabled - var actual = _sshMessageFactory.Create(messageNumber); - Assert.IsNotNull(actual); - Assert.AreEqual(typeof (NewKeysMessage), actual.GetType()); - } - - [TestMethod] - public void EnableActivatedMessagesShouldEnableMessagesThatWereEnabledPriorToInvokingDisableNonKeyExchangeMessages() - { - const byte messageNumber = 60; - - _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); - _sshMessageFactory.DisableNonKeyExchangeMessages(); - _sshMessageFactory.EnableActivatedMessages(); - - var actual = _sshMessageFactory.Create(messageNumber); - Assert.IsNotNull(actual); - Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType()); - } - - [TestMethod] - public void EnableActivatedMessagesShouldNotEnableMessagesThatWereDisabledPriorToInvokingDisableNonKeyExchangeMessages() - { - const byte messageNumber = 60; - - _sshMessageFactory.DisableNonKeyExchangeMessages(); - _sshMessageFactory.EnableActivatedMessages(); - - try - { - _sshMessageFactory.Create(messageNumber); - Assert.Fail(); - } - catch (SshException ex) - { - Assert.IsNull(ex.InnerException); - Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message); - } - } - - [TestMethod] - public void EnableActivatedMessagesShouldNotEnableMessagesThatWereDisabledAfterInvokingDisableNonKeyExchangeMessages() - { - const byte messageNumber = 60; - - _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); - _sshMessageFactory.DisableNonKeyExchangeMessages(); - _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); - _sshMessageFactory.EnableActivatedMessages(); - - try - { - _sshMessageFactory.Create(messageNumber); - Assert.Fail(); - } - catch (SshException ex) - { - Assert.IsNull(ex.InnerException); - Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message); - } - } - - [TestMethod] - public void EnableActivatedMessagesShouldThrowSshExceptionWhenAnothersMessageWithSameMessageNumberWasEnabledAfterInvokingDisableNonKeyExchangeMessages() - { - _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); - _sshMessageFactory.DisableNonKeyExchangeMessages(); - _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST"); - - try - { - _sshMessageFactory.EnableActivatedMessages(); - Assert.Fail(); - } - catch (SshException ex) - { - Assert.IsNull(ex.InnerException); - Assert.AreEqual("Cannot enable message 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ'. Message type 60 is already enabled for 'SSH_MSG_USERAUTH_INFO_REQUEST'.", ex.Message); - } - } - - [TestMethod] - public void EnableActivatedMessagesShouldLeaveMessagesEnabledThatWereEnabledAfterInvokingDisableNonKeyExchangeMessages() - { - const byte messageNumber = 60; - - _sshMessageFactory.DisableNonKeyExchangeMessages(); - _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); - _sshMessageFactory.EnableActivatedMessages(); - - var actual = _sshMessageFactory.Create(messageNumber); - Assert.IsNotNull(actual); - Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType()); - } - - [TestMethod] - public void HighestMessageNumberShouldCorrespondWithHighestSupportedMessageNumber() - { - var highestSupportMessageNumber = SshMessageFactory.AllMessages.Max(m => m.Number); - - Assert.AreEqual(highestSupportMessageNumber, SshMessageFactory.HighestMessageNumber); - } - - [TestMethod] - public void TotalMessageCountShouldBeTotalNumberOfSupportedMessages() - { - var totalNumberOfSupportedMessages = SshMessageFactory.AllMessages.Length; - - Assert.AreEqual(totalNumberOfSupportedMessages, SshMessageFactory.TotalMessageCount); - } - - [TestMethod] - [TestCategory("Performance")] - public void Performance_Ctor() - { - const int runCount = 100000; - - // warm-up - for (var i = 0; i < 3; i++) - { - var sshMessageFactory = new SshMessageFactory(); - var sshMessageFactoryOriginal = new SshMessageFactoryOriginal(); - } - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - var stopwatch = new Stopwatch(); - stopwatch.Start(); - - for (var i = 0; i < runCount; i++) - { - var sshMessageFactory = new SshMessageFactory(); - } - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - stopwatch.Stop(); - - Console.WriteLine(stopwatch.ElapsedMilliseconds); - - stopwatch.Reset(); - stopwatch.Start(); - - for (var i = 0; i < runCount; i++) - { - var sshMessageFactory = new SshMessageFactoryOriginal(); - } - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - stopwatch.Stop(); - - Console.WriteLine(stopwatch.ElapsedMilliseconds); - } - - [TestMethod] - [TestCategory("LongRunning")] - [TestCategory("Performance")] - public void Performance_Create() - { - const int runCount = 10000000; - const string messageName = "SSH_MSG_CHANNEL_CLOSE"; - - _sshMessageFactory.EnableAndActivateMessage(messageName); - _sshMessageFactoryOriginal.EnableAndActivateMessage(messageName); - - // warm-up - for (var i = 0; i < 3; i++) - { - _sshMessageFactory.Create(97); - _sshMessageFactoryOriginal.Create(97); - } - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - var stopwatch = new Stopwatch(); - stopwatch.Start(); - - for (var i = 0; i < runCount; i++) - { - var msg = _sshMessageFactory.Create(97); - if (msg == null) - Console.WriteLine(); - } - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - stopwatch.Stop(); - - Console.WriteLine(stopwatch.ElapsedMilliseconds); - - stopwatch.Reset(); - stopwatch.Start(); - - for (var i = 0; i < runCount; i++) - { - var msg = _sshMessageFactoryOriginal.Create(97); - if (msg == null) - Console.WriteLine(); - } - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - stopwatch.Stop(); - - Console.WriteLine(stopwatch.ElapsedMilliseconds); - } - - [TestMethod] - [TestCategory("LongRunning")] - [TestCategory("Performance")] - public void Performance_EnableAndActivateMessage() - { - const int runCount = 1000000; - const string messageName = "SSH_MSG_CHANNEL_CLOSE"; - - // warm-up - for (var i = 0; i < 3; i++) - { - _sshMessageFactory.EnableAndActivateMessage(messageName); - _sshMessageFactoryOriginal.EnableAndActivateMessage(messageName); - } - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - var stopwatch = new Stopwatch(); - stopwatch.Start(); - - for (var i = 0; i < runCount; i++) - _sshMessageFactory.EnableAndActivateMessage(messageName); - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - stopwatch.Stop(); - - Console.WriteLine(stopwatch.ElapsedMilliseconds); - - stopwatch.Reset(); - stopwatch.Start(); - - for (var i = 0; i < runCount; i++) - _sshMessageFactoryOriginal.EnableAndActivateMessage(messageName); - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - stopwatch.Stop(); - - Console.WriteLine(stopwatch.ElapsedMilliseconds); - } - - [TestMethod] - [TestCategory("LongRunning")] - [TestCategory("Performance")] - public void Performance_DisableAndDeactivateMessage() - { - const int runCount = 1000000; - const string messageName = "SSH_MSG_CHANNEL_CLOSE"; - - // warm-up - for (var i = 0; i < 3; i++) - { - _sshMessageFactory.DisableAndDeactivateMessage(messageName); - _sshMessageFactoryOriginal.DisableAndDeactivateMessage(messageName); - } - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - var stopwatch = new Stopwatch(); - stopwatch.Start(); - - for (var i = 0; i < runCount; i++) - _sshMessageFactory.DisableAndDeactivateMessage(messageName); - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - stopwatch.Stop(); - - Console.WriteLine(stopwatch.ElapsedMilliseconds); - - stopwatch.Reset(); - stopwatch.Start(); - - for (var i = 0; i < runCount; i++) - _sshMessageFactoryOriginal.DisableAndDeactivateMessage(messageName); - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - stopwatch.Stop(); - - Console.WriteLine(stopwatch.ElapsedMilliseconds); - } - - [TestMethod] - [TestCategory("LongRunning")] - [TestCategory("Performance")] - public void Performance_DisableNonKeyExchangeMessages() - { - const int runCount = 1000000; - - _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_BANNER"); - _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_DEBUG"); - _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_UNIMPLEMENTED"); - _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_SERVICE_ACCEPT"); - - _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_USERAUTH_BANNER"); - _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_DEBUG"); - _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_UNIMPLEMENTED"); - _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_SERVICE_ACCEPT"); - - // warm-up - for (var i = 0; i < 3; i++) - { - _sshMessageFactory.DisableNonKeyExchangeMessages(); - _sshMessageFactory.EnableActivatedMessages(); - - _sshMessageFactoryOriginal.DisableNonKeyExchangeMessages(); - _sshMessageFactoryOriginal.EnableActivatedMessages(); - } - - //Console.WriteLine("Starting test"); - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - var stopwatch = new Stopwatch(); - stopwatch.Start(); - - for (var i = 0; i < runCount; i++) - { - _sshMessageFactory.DisableNonKeyExchangeMessages(); - _sshMessageFactory.EnableActivatedMessages(); - } - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - stopwatch.Stop(); - - Console.WriteLine(stopwatch.ElapsedMilliseconds); - - stopwatch.Reset(); - stopwatch.Start(); - - for (var i = 0; i < runCount; i++) - { - _sshMessageFactoryOriginal.DisableNonKeyExchangeMessages(); - _sshMessageFactoryOriginal.EnableActivatedMessages(); - } - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - stopwatch.Stop(); - - Console.WriteLine(stopwatch.ElapsedMilliseconds); - } - - internal class SshMessageFactoryOriginal - { - private readonly IEnumerable _messagesMetadata; - - public SshMessageFactoryOriginal() - { - _messagesMetadata = new[] - { - new MessageMetadata {Name = "SSH_MSG_NEWKEYS", Number = 21, Type = typeof(NewKeysMessage)}, - new MessageMetadata - { - Name = "SSH_MSG_REQUEST_FAILURE", - Number = 82, - Type = typeof(RequestFailureMessage) - }, - new MessageMetadata {Name = "SSH_MSG_KEXINIT", Number = 20, Type = typeof(KeyExchangeInitMessage)}, - new MessageMetadata - { - Name = "SSH_MSG_CHANNEL_OPEN_FAILURE", - Number = 92, - Type = typeof(ChannelOpenFailureMessage) - }, - new MessageMetadata - { - Name = "SSH_MSG_CHANNEL_FAILURE", - Number = 100, - Type = typeof(ChannelFailureMessage) - }, - new MessageMetadata - { - Name = "SSH_MSG_CHANNEL_EXTENDED_DATA", - Number = 95, - Type = typeof(ChannelExtendedDataMessage) - }, - new MessageMetadata - { - Name = "SSH_MSG_CHANNEL_DATA", - Number = 94, - Type = typeof(ChannelDataMessage) - }, - new MessageMetadata - { - Name = "SSH_MSG_USERAUTH_REQUEST", - Number = 50, - Type = typeof(RequestMessage) - }, - new MessageMetadata - { - Name = "SSH_MSG_CHANNEL_REQUEST", - Number = 98, - Type = typeof(ChannelRequestMessage) - }, - new MessageMetadata - { - Name = "SSH_MSG_USERAUTH_BANNER", - Number = 53, - Type = typeof(BannerMessage) - }, - new MessageMetadata - { - Name = "SSH_MSG_USERAUTH_INFO_RESPONSE", - Number = 61, - Type = typeof(InformationResponseMessage) - }, - new MessageMetadata - { - Name = "SSH_MSG_USERAUTH_FAILURE", - Number = 51, - Type = typeof(FailureMessage) - }, - new MessageMetadata {Name = "SSH_MSG_DEBUG", Number = 4, Type = typeof(DebugMessage),}, - new MessageMetadata - { - Name = "SSH_MSG_KEXDH_INIT", - Number = 30, - Type = typeof(KeyExchangeDhInitMessage) - }, - new MessageMetadata - { - Name = "SSH_MSG_GLOBAL_REQUEST", - Number = 80, - Type = typeof(GlobalRequestMessage) - }, - new MessageMetadata - { - Name = "SSH_MSG_CHANNEL_OPEN", - Number = 90, - Type = typeof(ChannelOpenMessage) - }, - new MessageMetadata - { - Name = "SSH_MSG_CHANNEL_OPEN_CONFIRMATION", - Number = 91, - Type = typeof(ChannelOpenConfirmationMessage) - }, - new MessageMetadata - { - Name = "SSH_MSG_USERAUTH_INFO_REQUEST", - Number = 60, - Type = typeof(InformationRequestMessage) - }, - new MessageMetadata - { - Name = "SSH_MSG_UNIMPLEMENTED", - Number = 3, - Type = typeof(UnimplementedMessage) - }, - new MessageMetadata - { - Name = "SSH_MSG_REQUEST_SUCCESS", - Number = 81, - Type = typeof(RequestSuccessMessage) - }, - new MessageMetadata - { - Name = "SSH_MSG_CHANNEL_SUCCESS", - Number = 99, - Type = typeof(ChannelSuccessMessage) - }, - new MessageMetadata - { - Name = "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ", - Number = 60, - Type = typeof(PasswordChangeRequiredMessage) - }, - new MessageMetadata {Name = "SSH_MSG_DISCONNECT", Number = 1, Type = typeof(DisconnectMessage)}, - new MessageMetadata - { - Name = "SSH_MSG_SERVICE_REQUEST", - Number = 5, - Type = typeof(ServiceRequestMessage) - }, - new MessageMetadata - { - Name = "SSH_MSG_KEX_DH_GEX_REQUEST", - Number = 34, - Type = typeof(KeyExchangeDhGroupExchangeRequest) - }, - new MessageMetadata - { - Name = "SSH_MSG_KEX_DH_GEX_GROUP", - Number = 31, - Type = typeof(KeyExchangeDhGroupExchangeGroup) - }, - new MessageMetadata - { - Name = "SSH_MSG_USERAUTH_SUCCESS", - Number = 52, - Type = typeof(SuccessMessage) - }, - new MessageMetadata - { - Name = "SSH_MSG_USERAUTH_PK_OK", - Number = 60, - Type = typeof(PublicKeyMessage) - }, - new MessageMetadata {Name = "SSH_MSG_IGNORE", Number = 2, Type = typeof(IgnoreMessage)}, - new MessageMetadata - { - Name = "SSH_MSG_CHANNEL_WINDOW_ADJUST", - Number = 93, - Type = typeof(ChannelWindowAdjustMessage) - }, - new MessageMetadata - { - Name = "SSH_MSG_CHANNEL_EOF", - Number = 96, - Type = typeof(ChannelEofMessage) - }, - new MessageMetadata - { - Name = "SSH_MSG_CHANNEL_CLOSE", - Number = 97, - Type = typeof(ChannelCloseMessage) - }, - new MessageMetadata - { - Name = "SSH_MSG_SERVICE_ACCEPT", - Number = 6, - Type = typeof(ServiceAcceptMessage) - }, - new MessageMetadata - { - Name = "SSH_MSG_KEXDH_REPLY", - Number = 31, - Type = typeof(KeyExchangeDhReplyMessage) - }, - new MessageMetadata - { - Name = "SSH_MSG_KEX_DH_GEX_INIT", - Number = 32, - Type = typeof(KeyExchangeDhGroupExchangeInit) - }, - new MessageMetadata - { - Name = "SSH_MSG_KEX_DH_GEX_REPLY", - Number = 33, - Type = typeof(KeyExchangeDhGroupExchangeReply) - } - }; - } - - /// - /// Disables and deactivate all messages. - /// - public void Reset() - { - foreach (var messageMetadata in _messagesMetadata) - { - messageMetadata.Activated = messageMetadata.Enabled = false; - } - } - - public void EnableActivatedMessages() - { - foreach (var messageMetadata in _messagesMetadata) - { - if (messageMetadata.Activated) - messageMetadata.Enabled = true; - } - } - - public Message Create(byte messageNumber) - { - var messageMetadata = - (from m in _messagesMetadata where m.Number == messageNumber && m.Enabled && m.Activated select m) - .FirstOrDefault(); - if (messageMetadata == null) - throw new SshException(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid.", - messageNumber)); - - return messageMetadata.Type.CreateInstance(); - } - - public void DisableNonKeyExchangeMessages() - { - foreach (var messageMetadata in _messagesMetadata) - { - if (messageMetadata.Activated && messageMetadata.Number > 2 && - (messageMetadata.Number < 20 || messageMetadata.Number > 30)) - { - //Console.WriteLine("Disabling " + messageMetadata.Name + "..."); - - messageMetadata.Enabled = false; - } - } - } - - public void EnableAndActivateMessage(string messageName) - { - lock (_messagesMetadata) - { - var messagesMetadata = _messagesMetadata.Where(m => m.Name == messageName); - foreach (var messageMetadata in messagesMetadata) - messageMetadata.Enabled = messageMetadata.Activated = true; - } - } - - public void DisableAndDeactivateMessage(string messageName) - { - lock (_messagesMetadata) - { - var messagesMetadata = _messagesMetadata.Where(m => m.Name == messageName); - foreach (var messageMetadata in messagesMetadata) - messageMetadata.Enabled = messageMetadata.Activated = false; - } - } - - private class MessageMetadata - { - public string Name { get; set; } - - public byte Number { get; set; } - - public bool Enabled { get; set; } - - public bool Activated { get; set; } - - public Type Type { get; set; } - } - } - } -} diff --git a/test/Renci.SshNet.Tests/Classes/AbstractionsTest.cs b/test/Renci.SshNet.Tests/Classes/AbstractionsTest.cs new file mode 100644 index 000000000..90608d6b2 --- /dev/null +++ b/test/Renci.SshNet.Tests/Classes/AbstractionsTest.cs @@ -0,0 +1,63 @@ +using Renci.SshNet.Abstractions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Threading; + +namespace Renci.SshNet.Tests.Classes +{ + [TestClass] + public class AbstractionsTest + { + [TestMethod] + public void SocketAbstraction_CanWrite_ShouldReturnFalseWhenSocketIsNull() + { + Assert.IsFalse(SocketAbstraction.CanWrite(null)); + } + + [TestMethod] + public void CryptoAbstraction_GenerateRandom_ShouldPerformNoOpWhenDataIsZeroLength() + { + Assert.AreEqual(0, CryptoAbstraction.GenerateRandom(0).Length); + } + + [TestMethod] + public void CryptoAbstraction_GenerateRandom_ShouldGenerateRandomSequenceOfValues() + { + var dataLength = new Random().Next(1, 100); + + var dataA = CryptoAbstraction.GenerateRandom(dataLength); + var dataB = CryptoAbstraction.GenerateRandom(dataLength); + + Assert.AreEqual(dataLength, dataA.Length); + Assert.AreEqual(dataLength, dataB.Length); + + CollectionAssert.AreNotEqual(dataA, dataB); + } + + [TestMethod] + public void ThreadAbstraction_ExecuteThread_ShouldThrowArgumentNullExceptionWhenActionIsNull() + { + var ex = Assert.ThrowsException(() => ThreadAbstraction.ExecuteThread(null)); + + Assert.IsNull(ex.InnerException); + Assert.AreEqual("action", ex.ParamName); + } + + [TestMethod] + public void ThreadAbstraction_ExecuteThread_ShouldExecuteActionOnSeparateThread() + { + int threadId = 0; + using var waitHandle = new ManualResetEventSlim(); + + ThreadAbstraction.ExecuteThread(() => + { + threadId = Environment.CurrentManagedThreadId; + waitHandle.Set(); + }); + + Assert.IsTrue(waitHandle.Wait(1000)); + Assert.AreNotEqual(0, threadId); + Assert.AreNotEqual(Environment.CurrentManagedThreadId, threadId); + } + } +} diff --git a/test/Renci.SshNet.Shared.Tests/ForwardedPortStatusTest_Started.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortStatusTest_Started.cs similarity index 97% rename from test/Renci.SshNet.Shared.Tests/ForwardedPortStatusTest_Started.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortStatusTest_Started.cs index 7b82bb861..286b149b8 100644 --- a/test/Renci.SshNet.Shared.Tests/ForwardedPortStatusTest_Started.cs +++ b/test/Renci.SshNet.Tests/Classes/ForwardedPortStatusTest_Started.cs @@ -1,7 +1,7 @@ -using System; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace Renci.SshNet.Tests +#pragma warning disable SA1131 // Use readable conditions +namespace Renci.SshNet.Tests.Classes { [TestClass] public class ForwardedPortStatusTest_Started diff --git a/test/Renci.SshNet.Shared.Tests/ForwardedPortStatusTest_Starting.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortStatusTest_Starting.cs similarity index 97% rename from test/Renci.SshNet.Shared.Tests/ForwardedPortStatusTest_Starting.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortStatusTest_Starting.cs index 543406343..06946be18 100644 --- a/test/Renci.SshNet.Shared.Tests/ForwardedPortStatusTest_Starting.cs +++ b/test/Renci.SshNet.Tests/Classes/ForwardedPortStatusTest_Starting.cs @@ -1,7 +1,7 @@ -using System; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace Renci.SshNet.Tests +#pragma warning disable SA1131 // Use readable conditions +namespace Renci.SshNet.Tests.Classes { [TestClass] public class ForwardedPortStatusTest_Starting diff --git a/test/Renci.SshNet.Shared.Tests/ForwardedPortStatusTest_Stopped.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortStatusTest_Stopped.cs similarity index 97% rename from test/Renci.SshNet.Shared.Tests/ForwardedPortStatusTest_Stopped.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortStatusTest_Stopped.cs index c4e68ff36..a3836aa03 100644 --- a/test/Renci.SshNet.Shared.Tests/ForwardedPortStatusTest_Stopped.cs +++ b/test/Renci.SshNet.Tests/Classes/ForwardedPortStatusTest_Stopped.cs @@ -1,7 +1,7 @@ -using System; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace Renci.SshNet.Tests +#pragma warning disable SA1131 // Use readable conditions +namespace Renci.SshNet.Tests.Classes { [TestClass] public class ForwardedPortStatusTest_Stopped diff --git a/test/Renci.SshNet.Shared.Tests/ForwardedPortStatusTest_Stopping.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortStatusTest_Stopping.cs similarity index 98% rename from test/Renci.SshNet.Shared.Tests/ForwardedPortStatusTest_Stopping.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortStatusTest_Stopping.cs index d1edc7ef2..775ff711a 100644 --- a/test/Renci.SshNet.Shared.Tests/ForwardedPortStatusTest_Stopping.cs +++ b/test/Renci.SshNet.Tests/Classes/ForwardedPortStatusTest_Stopping.cs @@ -1,7 +1,9 @@ using System; + using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace Renci.SshNet.Tests +#pragma warning disable SA1131 // Use readable conditions +namespace Renci.SshNet.Tests.Classes { [TestClass] public class ForwardedPortStatusTest_Stopping diff --git a/test/Renci.SshNet.Tests/Classes/SshMessageFactoryTest.cs b/test/Renci.SshNet.Tests/Classes/SshMessageFactoryTest.cs new file mode 100644 index 000000000..ceca95818 --- /dev/null +++ b/test/Renci.SshNet.Tests/Classes/SshMessageFactoryTest.cs @@ -0,0 +1,423 @@ +using System; +using System.Globalization; +using System.Linq; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Common; +using Renci.SshNet.Messages.Authentication; +using Renci.SshNet.Messages.Transport; + +namespace Renci.SshNet.Tests.Classes +{ + [TestClass] + public class SshMessageFactoryTest + { + private SshMessageFactory _sshMessageFactory; + + [TestInitialize] + public void SetUp() + { + _sshMessageFactory = new SshMessageFactory(); + } + + [TestMethod] + public void CreateShouldThrowSshExceptionWhenMessageIsNotEnabled() + { + const byte messageNumber = 60; + + try + { + _sshMessageFactory.Create(messageNumber); + Assert.Fail(); + } + catch (SshException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message); + } + } + + [TestMethod] + public void CreateShouldThrowSshExceptionWhenMessageDoesNotExist_OutsideOfMessageNumberRange() + { + const byte messageNumber = 255; + + try + { + _sshMessageFactory.Create(messageNumber); + Assert.Fail(); + } + catch (SshException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not supported.", messageNumber), ex.Message); + } + } + + [TestMethod] + public void CreateShouldThrowSshExceptionWhenMessageDoesNotExist_WithinMessageNumberRange() + { + const byte messageNumber = 5; + + try + { + _sshMessageFactory.Create(messageNumber); + Assert.Fail(); + } + catch (SshException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not supported.", messageNumber), ex.Message); + } + } + + [TestMethod] + public void CreateShouldThrowSshExceptionWhenMessageIsNotActivated() + { + const byte messageNumber = 60; + const string messageName = "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"; + + _sshMessageFactory.EnableAndActivateMessage(messageName); + _sshMessageFactory.DisableAndDeactivateMessage(messageName); + + try + { + _sshMessageFactory.Create(messageNumber); + Assert.Fail(); + } + catch (SshException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message); + } + } + + [TestMethod] + public void CreateShouldReturnMessageInstanceCorrespondingToMessageNumberWhenMessageIsEnabledAndActivated() + { + const byte messageNumber = 60; + const string messageName = "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"; + + _sshMessageFactory.EnableAndActivateMessage(messageName); + + var actual = _sshMessageFactory.Create(messageNumber); + + Assert.IsNotNull(actual); + Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType()); + + _sshMessageFactory.DisableAndDeactivateMessage(messageName); + _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST"); + + actual = _sshMessageFactory.Create(messageNumber); + + Assert.IsNotNull(actual); + Assert.AreEqual(typeof(InformationRequestMessage), actual.GetType()); + } + + [TestMethod] + public void DisableAndDeactivateMessageShouldThrowSshExceptionWhenAnotherMessageWithSameMessageNumberIsEnabled() + { + _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); + + try + { + _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST"); + Assert.Fail(); + } + catch (SshException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("Cannot enable message 'SSH_MSG_USERAUTH_INFO_REQUEST'. Message type 60 is already enabled for 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ'.", ex.Message); + } + + // verify that the original message remains enabled + var actual = _sshMessageFactory.Create(60); + Assert.IsNotNull(actual); + Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType()); + } + + [TestMethod] + public void DisableAndDeactivateMessageShouldNotThrowExceptionWhenMessageIsAlreadyDisabled() + { + const byte messageNumber = 60; + + _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); + _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); + _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); + + // verify that message remains disabled + try + { + _sshMessageFactory.Create(messageNumber); + Assert.Fail(); + } + catch (SshException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message); + } + } + + [TestMethod] + public void DisableAndDeactivateMessageShouldNotThrowExceptionWhenMessageWasNeverEnabled() + { + const byte messageNumber = 60; + + _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); + + // verify that message is disabled + try + { + _sshMessageFactory.Create(messageNumber); + Assert.Fail(); + } + catch (SshException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message); + } + } + + [TestMethod] + public void DisableAndDeactivateMessageShouldThrowSshExceptionWhenMessageIsNotSupported() + { + const string messageName = "WHATEVER"; + + try + { + _sshMessageFactory.DisableAndDeactivateMessage("WHATEVER"); + Assert.Fail(); + } + catch (SshException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual(string.Format("Message '{0}' is not supported.", messageName), ex.Message); + } + } + + [TestMethod] + public void DisableAndDeactivateMessageShouldThrowArgumentNullExceptionWhenMessageNameIsNull() + { + const string messageName = null; + + try + { + _sshMessageFactory.DisableAndDeactivateMessage(messageName); + Assert.Fail(); + } + catch (ArgumentNullException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("messageName", ex.ParamName); + } + } + + [TestMethod] + public void EnableAndActivateMessageShouldThrowSshExceptionWhenAnotherMessageWithSameMessageNumberIsAlreadyEnabled() + { + _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); + + try + { + _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST"); + Assert.Fail(); + } + catch (SshException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("Cannot enable message 'SSH_MSG_USERAUTH_INFO_REQUEST'. Message type 60 is already enabled for 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ'.", ex.Message); + } + + // verify that the original message remains enabled + var actual = _sshMessageFactory.Create(60); + Assert.IsNotNull(actual); + Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType()); + } + + [TestMethod] + public void EnableAndActivateMessageShouldNotThrowExceptionWhenMessageIsAlreadyEnabled() + { + _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); + _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); + + var actual = _sshMessageFactory.Create(60); + Assert.IsNotNull(actual); + Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType()); + } + + [TestMethod] + public void EnableAndActivateMessageShouldThrowSshExceptionWhenMessageIsNotSupported() + { + const string messageName = "WHATEVER"; + + try + { + _sshMessageFactory.EnableAndActivateMessage("WHATEVER"); + Assert.Fail(); + } + catch (SshException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual(string.Format("Message '{0}' is not supported.", messageName), ex.Message); + } + } + + [TestMethod] + public void EnableAndActivateMessageShouldThrowArgumentNullExceptionWhenMessageNameIsNull() + { + const string messageName = null; + + try + { + _sshMessageFactory.EnableAndActivateMessage(messageName); + Assert.Fail(); + } + catch (ArgumentNullException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("messageName", ex.ParamName); + } + } + + [TestMethod] + public void DisableNonKeyExchangeMessagesShouldDisableNonKeyExchangeMessages() + { + const byte messageNumber = 60; + + _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); + _sshMessageFactory.DisableNonKeyExchangeMessages(strict: false); + + // verify that message is disabled + try + { + _sshMessageFactory.Create(messageNumber); + Assert.Fail(); + } + catch (SshException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message); + } + } + + [TestMethod] + public void DisableNonKeyExchangeMessagesShouldNotDisableKeyExchangeMessages() + { + const byte messageNumber = 21; + + _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_NEWKEYS"); + _sshMessageFactory.DisableNonKeyExchangeMessages(strict: false); + + // verify that message remains enabled + var actual = _sshMessageFactory.Create(messageNumber); + Assert.IsNotNull(actual); + Assert.AreEqual(typeof(NewKeysMessage), actual.GetType()); + } + + [TestMethod] + public void EnableActivatedMessagesShouldEnableMessagesThatWereEnabledPriorToInvokingDisableNonKeyExchangeMessages() + { + const byte messageNumber = 60; + + _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); + _sshMessageFactory.DisableNonKeyExchangeMessages(strict: false); + _sshMessageFactory.EnableActivatedMessages(); + + var actual = _sshMessageFactory.Create(messageNumber); + Assert.IsNotNull(actual); + Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType()); + } + + [TestMethod] + public void EnableActivatedMessagesShouldNotEnableMessagesThatWereDisabledPriorToInvokingDisableNonKeyExchangeMessages() + { + const byte messageNumber = 60; + + _sshMessageFactory.DisableNonKeyExchangeMessages(strict: false); + _sshMessageFactory.EnableActivatedMessages(); + + try + { + _sshMessageFactory.Create(messageNumber); + Assert.Fail(); + } + catch (SshException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message); + } + } + + [TestMethod] + public void EnableActivatedMessagesShouldNotEnableMessagesThatWereDisabledAfterInvokingDisableNonKeyExchangeMessages() + { + const byte messageNumber = 60; + + _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); + _sshMessageFactory.DisableNonKeyExchangeMessages(strict: false); + _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); + _sshMessageFactory.EnableActivatedMessages(); + + try + { + _sshMessageFactory.Create(messageNumber); + Assert.Fail(); + } + catch (SshException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message); + } + } + + [TestMethod] + public void EnableActivatedMessagesShouldThrowSshExceptionWhenAnothersMessageWithSameMessageNumberWasEnabledAfterInvokingDisableNonKeyExchangeMessages() + { + _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); + _sshMessageFactory.DisableNonKeyExchangeMessages(strict: false); + _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST"); + + try + { + _sshMessageFactory.EnableActivatedMessages(); + Assert.Fail(); + } + catch (SshException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("Cannot enable message 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ'. Message type 60 is already enabled for 'SSH_MSG_USERAUTH_INFO_REQUEST'.", ex.Message); + } + } + + [TestMethod] + public void EnableActivatedMessagesShouldLeaveMessagesEnabledThatWereEnabledAfterInvokingDisableNonKeyExchangeMessages() + { + const byte messageNumber = 60; + + _sshMessageFactory.DisableNonKeyExchangeMessages(strict: false); + _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); + _sshMessageFactory.EnableActivatedMessages(); + + var actual = _sshMessageFactory.Create(messageNumber); + Assert.IsNotNull(actual); + Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType()); + } + + [TestMethod] + public void HighestMessageNumberShouldCorrespondWithHighestSupportedMessageNumber() + { + var highestSupportMessageNumber = SshMessageFactory.AllMessages.Max(m => m.Number); + + Assert.AreEqual(highestSupportMessageNumber, SshMessageFactory.HighestMessageNumber); + } + + [TestMethod] + public void TotalMessageCountShouldBeTotalNumberOfSupportedMessages() + { + var totalNumberOfSupportedMessages = SshMessageFactory.AllMessages.Length; + + Assert.AreEqual(totalNumberOfSupportedMessages, SshMessageFactory.TotalMessageCount); + } + } +} diff --git a/test/Renci.SshNet.Tests/Common/HttpProxyStub.cs b/test/Renci.SshNet.Tests/Common/HttpProxyStub.cs deleted file mode 100644 index 7cc8c4715..000000000 --- a/test/Renci.SshNet.Tests/Common/HttpProxyStub.cs +++ /dev/null @@ -1,179 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net; -using System.Net.Sockets; -using System.Text; - -namespace Renci.SshNet.Tests.Common -{ - public class HttpProxyStub : IDisposable - { - private readonly IPEndPoint _endPoint; - private AsyncSocketListener _listener; - private HttpRequestParser _httpRequestParser; - private readonly IList _responses; - - public HttpProxyStub(IPEndPoint endPoint) - { - _endPoint = endPoint; - _responses = new List(); - } - - public HttpRequest HttpRequest - { - get - { - if (_httpRequestParser == null) - { - throw new InvalidOperationException("The proxy is not started."); - } - - return _httpRequestParser.HttpRequest; - } - } - - public IList Responses - { - get { return _responses; } - } - - public void Start() - { - _httpRequestParser = new HttpRequestParser(); - - _listener = new AsyncSocketListener(_endPoint); - _listener.BytesReceived += OnBytesReceived; - _listener.Start(); - } - - public void Stop() - { - _listener?.Stop(); - } - - public void Dispose() - { - Stop(); - GC.SuppressFinalize(this); - } - - private void OnBytesReceived(byte[] bytesReceived, Socket socket) - { - _httpRequestParser.ProcessData(bytesReceived); - - if (_httpRequestParser.CurrentState == HttpRequestParser.State.Content) - { - foreach (var response in Responses) - { - _ = socket.Send(response); - } - - socket.Shutdown(SocketShutdown.Send); - } - } - - private class HttpRequestParser - { - private readonly List _buffer; - private readonly HttpRequest _httpRequest; - - public enum State - { - RequestLine, - Headers, - Content - } - - public HttpRequestParser() - { - CurrentState = State.RequestLine; - _buffer = new List(); - _httpRequest = new HttpRequest(); - } - - public HttpRequest HttpRequest - { - get { return _httpRequest; } - } - - public State CurrentState { get; private set; } - - public void ProcessData(byte[] data) - { - var position = 0; - - while (position != data.Length) - { - if (CurrentState == State.RequestLine) - { - var requestLine = ReadLine(data, ref position); - if (requestLine != null) - { - _httpRequest.RequestLine = requestLine; - CurrentState = State.Headers; - } - } - - if (CurrentState == State.Headers) - { - var line = ReadLine(data, ref position); - if (line != null) - { - if (line.Length == 0) - { - CurrentState = State.Content; - } - else - { - _httpRequest.Headers.Add(line); - } - } - } - - if (CurrentState == State.Content) - { - if (position < data.Length) - { - var currentContent = _httpRequest.MessageBody; - var newBufferSize = currentContent.Length + (data.Length - position); - var copyBuffer = new byte[newBufferSize]; - Array.Copy(currentContent, copyBuffer, currentContent.Length); - Array.Copy(data, position, copyBuffer, currentContent.Length, data.Length - position); - _httpRequest.MessageBody = copyBuffer; - break; - } - } - } - } - - private string ReadLine(byte[] data, ref int position) - { - for (; position < data.Length; position++) - { - var b = data[position]; - if (b == '\n') - { - var buffer = _buffer.ToArray(); - var bytesInLine = buffer.Length; - - // when the previous byte was a CR, then do not include it in line - if (buffer.Length > 0 && buffer[buffer.Length - 1] == '\r') - { - bytesInLine -= 1; - } - - // clear the buffer - _buffer.Clear(); - - // move position up one position as we've processed the current byte - position++; - return Encoding.ASCII.GetString(buffer, 0, bytesInLine); - } - _buffer.Add(b); - } - - return null; - } - } - } -} diff --git a/test/Renci.SshNet.Tests/Common/HttpRequest.cs b/test/Renci.SshNet.Tests/Common/HttpRequest.cs deleted file mode 100644 index 56185fdd8..000000000 --- a/test/Renci.SshNet.Tests/Common/HttpRequest.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Collections.Generic; - -namespace Renci.SshNet.Tests.Common -{ - public class HttpRequest - { - public HttpRequest() - { - Headers = new List(); - MessageBody = new byte[0]; - } - - public string RequestLine { get; set; } - public IList Headers { get; set; } - public byte[] MessageBody { get; set; } - } -}