Files
Rob Hague 5b8382de26 Serialise packets into a buffer (#1792)
A byte array is allocated to hold each plaintext packet. This removes that by adding
a buffer for that purpose.
2026-05-05 13:41:35 +02:00

364 lines
12 KiB
C#

using System;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Messages.Connection;
using Renci.SshNet.Messages.Transport;
using Renci.SshNet.Tests.Common;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class SessionTest_Connected : SessionTest_ConnectedBase
{
private IgnoreMessage _ignoreMessage;
protected override void SetupData()
{
base.SetupData();
var data = new byte[10];
Random.NextBytes(data);
_ignoreMessage = new IgnoreMessage(data);
}
protected override void Act()
{
}
[TestMethod]
public void ClientVersionIsRenciSshNet()
{
Assert.IsTrue(Regex.IsMatch(
Session.ClientVersion,
// Ends with e.g. 2024.1.1 plus some optional metadata not containing '-'
@"^SSH-2\.0-Renci\.SshNet\.SshClient\.\d{4}\.\d+\.\d+(_[a-zA-Z0-9_\.]+)?$"));
}
[TestMethod]
public void IncludeStrictKexPseudoAlgorithmInInitKex()
{
Assert.IsTrue(FirstKexReceived.Wait(1000));
Assert.IsNotEmpty(ServerBytesReceivedRegister);
var kexInitMessage = new KeyExchangeInitMessage();
kexInitMessage.Load(ServerBytesReceivedRegister[0], 4 + 1 + 1, ServerBytesReceivedRegister[0].Length - 4 - 1 - 1);
Assert.IsTrue(kexInitMessage.KeyExchangeAlgorithms.Contains("kex-strict-c-v00@openssh.com"));
}
[TestMethod]
public void ShouldNotIncludeStrictKexPseudoAlgorithmInSubsequentKex()
{
Assert.IsTrue(FirstKexReceived.Wait(1000));
using var subsequentKexReceived = new ManualResetEventSlim();
bool kexContainsPseudoAlg = true;
ServerListener.BytesReceived += ServerListener_BytesReceived;
void ServerListener_BytesReceived(byte[] bytesReceived, Socket socket)
{
if (bytesReceived.Length > 5 && bytesReceived[5] == 20)
{
// SSH_MSG_KEXINIT = 20
var kexInitMessage = new KeyExchangeInitMessage();
kexInitMessage.Load(bytesReceived, 6, bytesReceived.Length - 6);
kexContainsPseudoAlg = kexInitMessage.KeyExchangeAlgorithms.Contains("kex-strict-c-v00@openssh.com");
subsequentKexReceived.Set();
}
}
Session.SendMessage(Session.ClientInitMessage);
Assert.IsTrue(subsequentKexReceived.Wait(1000));
Assert.IsFalse(kexContainsPseudoAlg);
ServerListener.BytesReceived -= ServerListener_BytesReceived;
}
[TestMethod]
public void ConnectionInfoShouldReturnConnectionInfoPassedThroughConstructor()
{
Assert.AreSame(ConnectionInfo, Session.ConnectionInfo);
}
[TestMethod]
public void IsConnectedShouldReturnTrue()
{
Assert.IsTrue(Session.IsConnected);
}
[TestMethod]
public void SendMessageShouldSendPacketToServer()
{
Thread.Sleep(100);
ServerBytesReceivedRegister.Clear();
Session.SendMessage(_ignoreMessage);
// give session time to process message
Thread.Sleep(100);
Assert.HasCount(1, ServerBytesReceivedRegister);
}
[TestMethod]
[DataRow(true)]
[DataRow(false)]
public void UnknownGlobalRequestWithWantReply(bool wantReply)
{
Thread.Sleep(100);
ServerBytesReceivedRegister.Clear();
var globalRequest =
new GlobalRequestMessage(Encoding.ASCII.GetBytes("unknown-request"), wantReply).GetPacket(8, null);
ServerSocket.Send(globalRequest, 4, globalRequest.Length - 4, SocketFlags.None);
Thread.Sleep(100);
if (wantReply)
{
// Should have sent a failure reply.
Assert.HasCount(1, ServerBytesReceivedRegister);
Assert.AreEqual(82, ServerBytesReceivedRegister[0][5], "Expected to have sent SSH_MSG_REQUEST_FAILURE(82)");
}
else
{
// Should not have sent any reply.
Assert.IsEmpty(ServerBytesReceivedRegister);
}
Assert.IsEmpty(ErrorOccurredRegister);
}
[TestMethod]
public void SessionIdShouldReturnExchangeHashCalculatedFromKeyExchangeInitMessage()
{
Assert.IsNotNull(Session.SessionId);
Assert.AreSame(SessionId, Session.SessionId);
}
[TestMethod]
public void ServerVersionShouldNotReturnNull()
{
Assert.IsNotNull(Session.ServerVersion);
Assert.AreEqual("SSH-2.0-OurServerStub", Session.ServerVersion);
}
[TestMethod]
public void WaitOnHandle_WaitHandle_ShouldThrowArgumentNullExceptionWhenWaitHandleIsNull()
{
const WaitHandle waitHandle = null;
try
{
Session.WaitOnHandle(waitHandle);
Assert.Fail();
}
catch (ArgumentNullException ex)
{
Assert.IsNull(ex.InnerException);
Assert.AreEqual("waitHandle", ex.ParamName);
}
}
[TestMethod]
public void WaitOnHandle_WaitHandleAndTimeout_ShouldThrowArgumentNullExceptionWhenWaitHandleIsNull()
{
const WaitHandle waitHandle = null;
var timeout = TimeSpan.FromMinutes(5);
try
{
Session.WaitOnHandle(waitHandle, timeout);
Assert.Fail();
}
catch (ArgumentNullException ex)
{
Assert.IsNull(ex.InnerException);
Assert.AreEqual("waitHandle", ex.ParamName);
}
}
[TestMethod]
public void ISession_ConnectionInfoShouldReturnConnectionInfoPassedThroughConstructor()
{
var session = (ISession)Session;
Assert.AreSame(ConnectionInfo, session.ConnectionInfo);
}
[TestMethod]
public void ISession_MessageListenerCompletedShouldNotBeSignaled()
{
var session = (ISession)Session;
Assert.IsNotNull(session.MessageListenerCompleted);
Assert.IsFalse(session.MessageListenerCompleted.WaitOne(0));
}
[TestMethod]
public void ISession_SendMessageShouldSendPacketToServer()
{
Thread.Sleep(100);
var session = (ISession)Session;
ServerBytesReceivedRegister.Clear();
session.SendMessage(_ignoreMessage);
// give session time to process message
Thread.Sleep(100);
Assert.HasCount(1, ServerBytesReceivedRegister);
}
[TestMethod]
public void ISession_TrySendMessageShouldSendPacketToServerAndReturnTrue()
{
Thread.Sleep(100);
var session = (ISession)Session;
ServerBytesReceivedRegister.Clear();
var actual = session.TrySendMessage(new IgnoreMessage());
// give session time to process message
Thread.Sleep(100);
Assert.IsTrue(actual);
Assert.HasCount(1, ServerBytesReceivedRegister);
}
[TestMethod]
public void ISession_WaitOnHandleShouldThrowArgumentNullExceptionWhenWaitHandleIsNull()
{
const WaitHandle waitHandle = null;
var session = (ISession)Session;
try
{
session.WaitOnHandle(waitHandle);
Assert.Fail();
}
catch (ArgumentNullException ex)
{
Assert.IsNull(ex.InnerException);
Assert.AreEqual("waitHandle", ex.ParamName);
}
}
[TestMethod]
public void ISession_TryWait_WaitHandleAndTimeout_ShouldReturnSuccessIfWaitHandleIsSignaled()
{
var session = (ISession)Session;
using var waitHandle = new ManualResetEvent(true);
var result = session.TryWait(waitHandle, TimeSpan.Zero);
Assert.AreEqual(WaitResult.Success, result);
}
[TestMethod]
public void ISession_TryWait_WaitHandleAndTimeout_ShouldReturnTimedOutIfWaitHandleIsNotSignaled()
{
var session = (ISession)Session;
using var waitHandle = new ManualResetEvent(false);
var result = session.TryWait(waitHandle, TimeSpan.Zero);
Assert.AreEqual(WaitResult.TimedOut, result);
}
[TestMethod]
public void ISession_TryWait_WaitHandleAndTimeout_ShouldThrowArgumentNullExceptionWhenWaitHandleIsNull()
{
var session = (ISession)Session;
const WaitHandle waitHandle = null;
try
{
_ = session.TryWait(waitHandle, Timeout.InfiniteTimeSpan);
Assert.Fail();
}
catch (ArgumentNullException ex)
{
Assert.IsNull(ex.InnerException);
Assert.AreEqual("waitHandle", ex.ParamName);
}
}
[TestMethod]
public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnSuccessIfWaitHandleIsSignaled()
{
var session = (ISession)Session;
using var waitHandle = new ManualResetEvent(true);
var result = session.TryWait(waitHandle, TimeSpan.Zero, out var exception);
Assert.AreEqual(WaitResult.Success, result);
Assert.IsNull(exception);
}
[TestMethod]
public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnTimedOutIfWaitHandleIsNotSignaled()
{
var session = (ISession)Session;
using var waitHandle = new ManualResetEvent(false);
var result = session.TryWait(waitHandle, TimeSpan.Zero, out var exception);
Assert.AreEqual(WaitResult.TimedOut, result);
Assert.IsNull(exception);
}
[TestMethod]
public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldThrowArgumentNullExceptionWhenWaitHandleIsNull()
{
var session = (ISession)Session;
const WaitHandle waitHandle = null;
Exception exception = null;
try
{
session.TryWait(waitHandle, Timeout.InfiniteTimeSpan, out exception);
Assert.Fail();
}
catch (ArgumentNullException ex)
{
Assert.IsNull(ex.InnerException);
Assert.AreEqual("waitHandle", ex.ParamName);
Assert.IsNull(exception);
}
}
[TestMethod]
public void ClientSocketShouldBeConnected()
{
Assert.IsNotNull(ClientSocket);
Assert.IsTrue(ClientSocket.Connected);
}
[TestMethod]
public void CreateConnectorOnServiceFactoryShouldHaveBeenInvokedOnce()
{
ServiceFactoryMock.Verify(p => p.CreateConnector(ConnectionInfo, SocketFactoryMock.Object), Times.Once());
}
[TestMethod]
public void ConnectorOnConnectorShouldHaveBeenInvokedOnce()
{
ConnectorMock.Verify(p => p.Connect(ConnectionInfo), Times.Once());
}
}
}