Port shared tests folder (#1467)

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.

Co-authored-by: Wojciech Nagórski <wojtpl2@gmail.com>
This commit is contained in:
Rob Hague
2024-08-12 09:33:01 +02:00
committed by GitHub
parent a067e2852a
commit 1af01692fe
19 changed files with 502 additions and 1613 deletions
@@ -292,7 +292,7 @@ namespace Renci.SshNet.Abstractions
{
if (IsErrorResumable(ex.SocketErrorCode))
{
ThreadAbstraction.Sleep(30);
Thread.Sleep(30);
continue;
}
@@ -346,7 +346,7 @@ namespace Renci.SshNet.Abstractions
if (IsErrorResumable(ex.SocketErrorCode))
{
// socket buffer is probably full, wait and try again
ThreadAbstraction.Sleep(30);
Thread.Sleep(30);
}
else
{
@@ -6,15 +6,6 @@ namespace Renci.SshNet.Abstractions
{
internal static class ThreadAbstraction
{
/// <summary>
/// Suspends the current thread for the specified number of milliseconds.
/// </summary>
/// <param name="millisecondsTimeout">The number of milliseconds for which the thread is suspended.</param>
public static void Sleep(int millisecondsTimeout)
{
Thread.Sleep(millisecondsTimeout);
}
/// <summary>
/// Creates and starts a long-running <see cref="Task"/> for the specified <see cref="Action"/>.
/// </summary>
+2 -2
View File
@@ -16,7 +16,7 @@ namespace Renci.SshNet
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<KeyExchangeInitMessage>(0, "SSH_MSG_KEXINIT", 20),
new MessageMetadata<NewKeysMessage>(1, "SSH_MSG_NEWKEYS", 21),
@@ -263,7 +263,7 @@ namespace Renci.SshNet
currentEnabledForMessageName));
}
private abstract class MessageMetadata
internal abstract class MessageMetadata
{
protected MessageMetadata(byte id, string name, byte number)
{
@@ -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));
}
}
}
@@ -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]);
}
}
}
@@ -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();
}
}
}
@@ -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);
}
}
}
@@ -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));
}
}
}
@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<SharedGUID>fae3948f-a438-458e-8e0e-7f6e39a5dd8a</SharedGUID>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<Import_RootNamespace>Renci.SshNet.Tests</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)Abstractions\CryptoAbstraction_GenerateRandom.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Abstractions\DnsAbstraction_GetHostAddresses.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Abstractions\FileSystemAbstraction_EnumerateFiles.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Abstractions\SocketAbstraction_CanWrite.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Abstractions\ThreadAbstraction_ExecuteThread.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ForwardedPortStatusTest_Started.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ForwardedPortStatusTest_Starting.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ForwardedPortStatusTest_Stopped.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ForwardedPortStatusTest_Stopping.cs" />
<Compile Include="$(MSBuildThisFileDirectory)SshMessageFactoryTest.cs" />
</ItemGroup>
</Project>
@@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>fae3948f-a438-458e-8e0e-7f6e39a5dd8a</ProjectGuid>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<PropertyGroup />
<Import Project="Renci.SshNet.Shared.Tests.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
</Project>
@@ -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<MessageMetadata> _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)
}
};
}
/// <summary>
/// Disables and deactivate all messages.
/// </summary>
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<Message>();
}
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; }
}
}
}
}
@@ -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<ArgumentNullException>(() => 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);
}
}
}
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
}
}
}
@@ -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<byte[]> _responses;
public HttpProxyStub(IPEndPoint endPoint)
{
_endPoint = endPoint;
_responses = new List<byte[]>();
}
public HttpRequest HttpRequest
{
get
{
if (_httpRequestParser == null)
{
throw new InvalidOperationException("The proxy is not started.");
}
return _httpRequestParser.HttpRequest;
}
}
public IList<byte[]> 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<byte> _buffer;
private readonly HttpRequest _httpRequest;
public enum State
{
RequestLine,
Headers,
Content
}
public HttpRequestParser()
{
CurrentState = State.RequestLine;
_buffer = new List<byte>();
_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;
}
}
}
}
@@ -1,17 +0,0 @@
using System.Collections.Generic;
namespace Renci.SshNet.Tests.Common
{
public class HttpRequest
{
public HttpRequest()
{
Headers = new List<string>();
MessageBody = new byte[0];
}
public string RequestLine { get; set; }
public IList<string> Headers { get; set; }
public byte[] MessageBody { get; set; }
}
}