mirror of
https://github.com/sshnet/SSH.NET.git
synced 2026-09-10 09:15:47 +00:00
Significantly improve performance of ShellStream's Expect methods (#1207)
* Significantly improved performance and fixed bug with ShellStream's Expect methods. * Fix whitespace. * Fixed test. * Improve ShellStream Expect * Fixed typo. * Doubled expectBuffer's default size and added a large expect test. * Added guard clauses to ShellStream constructor and adjusted Common_CreateMoreChannelsThanMaxSessions test. * Fixed XMLDoc spelling mistakes. --------- Co-authored-by: Wojciech Nagórski <wojtpl2@gmail.com> Co-authored-by: Wojciech Nagórski <wojciech.nagorski@intel.com>
This commit is contained in:
committed by
GitHub
parent
7d357e8203
commit
bcaf354ccb
@@ -114,6 +114,7 @@ namespace Renci.SshNet
|
||||
/// <param name="height">The terminal height in pixels.</param>
|
||||
/// <param name="terminalModeValues">The terminal mode values.</param>
|
||||
/// <param name="bufferSize">Size of the buffer.</param>
|
||||
/// <param name="expectSize">Size of the expect buffer.</param>
|
||||
/// <returns>
|
||||
/// The created <see cref="ShellStream"/> instance.
|
||||
/// </returns>
|
||||
@@ -135,7 +136,8 @@ namespace Renci.SshNet
|
||||
uint width,
|
||||
uint height,
|
||||
IDictionary<TerminalModes, uint> terminalModeValues,
|
||||
int bufferSize);
|
||||
int bufferSize,
|
||||
int expectSize);
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="IRemotePathTransformation"/> that encloses a path in double quotes, and escapes
|
||||
|
||||
@@ -187,6 +187,7 @@ namespace Renci.SshNet
|
||||
/// <param name="height">The terminal height in pixels.</param>
|
||||
/// <param name="terminalModeValues">The terminal mode values.</param>
|
||||
/// <param name="bufferSize">The size of the buffer.</param>
|
||||
/// <param name="expectSize">The size of the expect buffer.</param>
|
||||
/// <returns>
|
||||
/// The created <see cref="ShellStream"/> instance.
|
||||
/// </returns>
|
||||
@@ -194,16 +195,16 @@ namespace Renci.SshNet
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The <c>TERM</c> environment variable contains an identifier for the text window's capabilities.
|
||||
/// You can get a detailed list of these cababilities by using the ‘infocmp’ command.
|
||||
/// You can get a detailed list of these capabilities by using the ‘infocmp’ command.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The column/row dimensions override the pixel dimensions(when non-zero). Pixel dimensions refer
|
||||
/// to the drawable area of the window.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public ShellStream CreateShellStream(ISession session, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint> terminalModeValues, int bufferSize)
|
||||
public ShellStream CreateShellStream(ISession session, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint> terminalModeValues, int bufferSize, int expectSize)
|
||||
{
|
||||
return new ShellStream(session, terminalName, columns, rows, width, height, terminalModeValues, bufferSize);
|
||||
return new ShellStream(session, terminalName, columns, rows, width, height, terminalModeValues, bufferSize, expectSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -22,6 +22,8 @@ namespace Renci.SshNet
|
||||
private readonly Encoding _encoding;
|
||||
private readonly int _bufferSize;
|
||||
private readonly Queue<byte> _incoming;
|
||||
private readonly int _expectSize;
|
||||
private readonly Queue<byte> _expect;
|
||||
private readonly Queue<byte> _outgoing;
|
||||
private IChannelSession _channel;
|
||||
private AutoResetEvent _dataReceived = new AutoResetEvent(initialState: false);
|
||||
@@ -76,15 +78,28 @@ namespace Renci.SshNet
|
||||
/// <param name="height">The terminal height in pixels.</param>
|
||||
/// <param name="terminalModeValues">The terminal mode values.</param>
|
||||
/// <param name="bufferSize">The size of the buffer.</param>
|
||||
/// <param name="expectSize">The size of the expect buffer.</param>
|
||||
/// <exception cref="SshException">The channel could not be opened.</exception>
|
||||
/// <exception cref="SshException">The pseudo-terminal request was not accepted by the server.</exception>
|
||||
/// <exception cref="SshException">The request to start a shell was not accepted by the server.</exception>
|
||||
internal ShellStream(ISession session, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint> terminalModeValues, int bufferSize)
|
||||
internal ShellStream(ISession session, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint> terminalModeValues, int bufferSize, int expectSize)
|
||||
{
|
||||
if (bufferSize <= 0)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(bufferSize)} must be between 1 and {int.MaxValue}.");
|
||||
}
|
||||
|
||||
if (expectSize <= 0)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(expectSize)} must be between 1 and {int.MaxValue}.");
|
||||
}
|
||||
|
||||
_encoding = session.ConnectionInfo.Encoding;
|
||||
_session = session;
|
||||
_bufferSize = bufferSize;
|
||||
_incoming = new Queue<byte>();
|
||||
_expectSize = expectSize;
|
||||
_expect = new Queue<byte>(_expectSize);
|
||||
_outgoing = new Queue<byte>();
|
||||
|
||||
_channel = _session.CreateChannelSession();
|
||||
@@ -248,35 +263,40 @@ namespace Renci.SshNet
|
||||
public void Expect(TimeSpan timeout, params ExpectAction[] expectActions)
|
||||
{
|
||||
var expectedFound = false;
|
||||
var text = string.Empty;
|
||||
var matchText = string.Empty;
|
||||
|
||||
do
|
||||
{
|
||||
lock (_incoming)
|
||||
{
|
||||
if (_incoming.Count > 0)
|
||||
if (_expect.Count > 0)
|
||||
{
|
||||
text = _encoding.GetString(_incoming.ToArray(), 0, _incoming.Count);
|
||||
matchText = _encoding.GetString(_expect.ToArray(), 0, _expect.Count);
|
||||
}
|
||||
|
||||
if (text.Length > 0)
|
||||
if (matchText.Length > 0)
|
||||
{
|
||||
foreach (var expectAction in expectActions)
|
||||
{
|
||||
var match = expectAction.Expect.Match(text);
|
||||
var match = expectAction.Expect.Match(matchText);
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
var result = text.Substring(0, match.Index + match.Length);
|
||||
var charCount = _encoding.GetByteCount(result);
|
||||
var returnText = matchText.Substring(0, match.Index + match.Length);
|
||||
var returnLength = _encoding.GetByteCount(returnText);
|
||||
|
||||
for (var i = 0; i < charCount && _incoming.Count > 0; i++)
|
||||
// Remove processed items from the queue
|
||||
for (var i = 0; i < returnLength && _incoming.Count > 0; i++)
|
||||
{
|
||||
// Remove processed items from the queue
|
||||
if (_expect.Count == _incoming.Count)
|
||||
{
|
||||
_ = _expect.Dequeue();
|
||||
}
|
||||
|
||||
_ = _incoming.Dequeue();
|
||||
}
|
||||
|
||||
expectAction.Action(result);
|
||||
expectAction.Action(returnText);
|
||||
expectedFound = true;
|
||||
}
|
||||
}
|
||||
@@ -349,27 +369,33 @@ namespace Renci.SshNet
|
||||
/// </returns>
|
||||
public string Expect(Regex regex, TimeSpan timeout)
|
||||
{
|
||||
var result = string.Empty;
|
||||
var matchText = string.Empty;
|
||||
string returnText;
|
||||
|
||||
while (true)
|
||||
{
|
||||
lock (_incoming)
|
||||
{
|
||||
if (_incoming.Count > 0)
|
||||
if (_expect.Count > 0)
|
||||
{
|
||||
result = _encoding.GetString(_incoming.ToArray(), 0, _incoming.Count);
|
||||
matchText = _encoding.GetString(_expect.ToArray(), 0, _expect.Count);
|
||||
}
|
||||
|
||||
var match = regex.Match(result);
|
||||
var match = regex.Match(matchText);
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
result = result.Substring(0, match.Index + match.Length);
|
||||
var charCount = _encoding.GetByteCount(result);
|
||||
returnText = matchText.Substring(0, match.Index + match.Length);
|
||||
var returnLength = _encoding.GetByteCount(returnText);
|
||||
|
||||
// Remove processed items from the queue
|
||||
for (var i = 0; i < charCount && _incoming.Count > 0; i++)
|
||||
for (var i = 0; i < returnLength && _incoming.Count > 0; i++)
|
||||
{
|
||||
if (_expect.Count == _incoming.Count)
|
||||
{
|
||||
_ = _expect.Dequeue();
|
||||
}
|
||||
|
||||
_ = _incoming.Dequeue();
|
||||
}
|
||||
|
||||
@@ -390,7 +416,7 @@ namespace Renci.SshNet
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return returnText;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -446,7 +472,8 @@ namespace Renci.SshNet
|
||||
public IAsyncResult BeginExpect(TimeSpan timeout, AsyncCallback callback, object state, params ExpectAction[] expectActions)
|
||||
#pragma warning restore CA1859 // Use concrete types when possible for improved performance
|
||||
{
|
||||
var text = string.Empty;
|
||||
var matchText = string.Empty;
|
||||
string returnText;
|
||||
|
||||
// Create new AsyncResult object
|
||||
var asyncResult = new ExpectAsyncResult(callback, state);
|
||||
@@ -461,31 +488,36 @@ namespace Renci.SshNet
|
||||
{
|
||||
lock (_incoming)
|
||||
{
|
||||
if (_incoming.Count > 0)
|
||||
if (_expect.Count > 0)
|
||||
{
|
||||
text = _encoding.GetString(_incoming.ToArray(), 0, _incoming.Count);
|
||||
matchText = _encoding.GetString(_expect.ToArray(), 0, _expect.Count);
|
||||
}
|
||||
|
||||
if (text.Length > 0)
|
||||
if (matchText.Length > 0)
|
||||
{
|
||||
foreach (var expectAction in expectActions)
|
||||
{
|
||||
var match = expectAction.Expect.Match(text);
|
||||
var match = expectAction.Expect.Match(matchText);
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
var result = text.Substring(0, match.Index + match.Length);
|
||||
var charCount = _encoding.GetByteCount(result);
|
||||
returnText = matchText.Substring(0, match.Index + match.Length);
|
||||
var returnLength = _encoding.GetByteCount(returnText);
|
||||
|
||||
for (var i = 0; i < match.Index + match.Length && _incoming.Count > 0; i++)
|
||||
// Remove processed items from the queue
|
||||
for (var i = 0; i < returnLength && _incoming.Count > 0; i++)
|
||||
{
|
||||
// Remove processed items from the queue
|
||||
if (_expect.Count == _incoming.Count)
|
||||
{
|
||||
_ = _expect.Dequeue();
|
||||
}
|
||||
|
||||
_ = _incoming.Dequeue();
|
||||
}
|
||||
|
||||
expectAction.Action(result);
|
||||
expectAction.Action(returnText);
|
||||
callback?.Invoke(asyncResult);
|
||||
expectActionResult = result;
|
||||
expectActionResult = returnText;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -584,6 +616,11 @@ namespace Renci.SshNet
|
||||
// remove processed bytes from the queue
|
||||
for (var i = 0; i < bytesProcessed; i++)
|
||||
{
|
||||
if (_expect.Count == _incoming.Count)
|
||||
{
|
||||
_ = _expect.Dequeue();
|
||||
}
|
||||
|
||||
_ = _incoming.Dequeue();
|
||||
}
|
||||
|
||||
@@ -620,6 +657,7 @@ namespace Renci.SshNet
|
||||
lock (_incoming)
|
||||
{
|
||||
text = _encoding.GetString(_incoming.ToArray(), 0, _incoming.Count);
|
||||
_expect.Clear();
|
||||
_incoming.Clear();
|
||||
}
|
||||
|
||||
@@ -649,6 +687,11 @@ namespace Renci.SshNet
|
||||
{
|
||||
for (; i < count && _incoming.Count > 0; i++)
|
||||
{
|
||||
if (_expect.Count == _incoming.Count)
|
||||
{
|
||||
_ = _expect.Dequeue();
|
||||
}
|
||||
|
||||
buffer[offset + i] = _incoming.Dequeue();
|
||||
}
|
||||
}
|
||||
@@ -800,6 +843,12 @@ namespace Renci.SshNet
|
||||
foreach (var b in e.Data)
|
||||
{
|
||||
_incoming.Enqueue(b);
|
||||
if (_expect.Count == _expectSize)
|
||||
{
|
||||
_ = _expect.Dequeue();
|
||||
}
|
||||
|
||||
_expect.Enqueue(b);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -407,7 +407,7 @@ namespace Renci.SshNet
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The <c>TERM</c> environment variable contains an identifier for the text window's capabilities.
|
||||
/// You can get a detailed list of these cababilities by using the ‘infocmp’ command.
|
||||
/// You can get a detailed list of these capabilities by using the ‘infocmp’ command.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The column/row dimensions override the pixel dimensions(when nonzero). Pixel dimensions refer
|
||||
@@ -416,7 +416,38 @@ namespace Renci.SshNet
|
||||
/// </remarks>
|
||||
public ShellStream CreateShellStream(string terminalName, uint columns, uint rows, uint width, uint height, int bufferSize)
|
||||
{
|
||||
return CreateShellStream(terminalName, columns, rows, width, height, bufferSize, terminalModeValues: null);
|
||||
return CreateShellStream(terminalName, columns, rows, width, height, bufferSize, bufferSize * 2, terminalModeValues: null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the shell stream.
|
||||
/// </summary>
|
||||
/// <param name="terminalName">The <c>TERM</c> environment variable.</param>
|
||||
/// <param name="columns">The terminal width in columns.</param>
|
||||
/// <param name="rows">The terminal width in rows.</param>
|
||||
/// <param name="width">The terminal width in pixels.</param>
|
||||
/// <param name="height">The terminal height in pixels.</param>
|
||||
/// <param name="bufferSize">The size of the buffer.</param>
|
||||
/// <param name="expectSize">The size of the expect buffer.</param>
|
||||
/// <returns>
|
||||
/// The created <see cref="ShellStream"/> instance.
|
||||
/// </returns>
|
||||
/// <exception cref="SshConnectionException">Client is not connected.</exception>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The <c>TERM</c> environment variable contains an identifier for the text window's capabilities.
|
||||
/// You can get a detailed list of these capabilities by using the ‘infocmp’ command.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The column/row dimensions override the pixel dimensions(when non-zero). Pixel dimensions refer
|
||||
/// to the drawable area of the window.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public ShellStream CreateShellStream(string terminalName, uint columns, uint rows, uint width, uint height, int bufferSize, int expectSize)
|
||||
{
|
||||
EnsureSessionIsOpen();
|
||||
|
||||
return CreateShellStream(terminalName, columns, rows, width, height, bufferSize, expectSize, terminalModeValues: null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -436,7 +467,7 @@ namespace Renci.SshNet
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The <c>TERM</c> environment variable contains an identifier for the text window's capabilities.
|
||||
/// You can get a detailed list of these cababilities by using the ‘infocmp’ command.
|
||||
/// You can get a detailed list of these capabilities by using the ‘infocmp’ command.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The column/row dimensions override the pixel dimensions(when non-zero). Pixel dimensions refer
|
||||
@@ -447,7 +478,39 @@ namespace Renci.SshNet
|
||||
{
|
||||
EnsureSessionIsOpen();
|
||||
|
||||
return ServiceFactory.CreateShellStream(Session, terminalName, columns, rows, width, height, terminalModeValues, bufferSize);
|
||||
return CreateShellStream(terminalName, columns, rows, width, height, bufferSize, bufferSize * 2, terminalModeValues);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the shell stream.
|
||||
/// </summary>
|
||||
/// <param name="terminalName">The <c>TERM</c> environment variable.</param>
|
||||
/// <param name="columns">The terminal width in columns.</param>
|
||||
/// <param name="rows">The terminal width in rows.</param>
|
||||
/// <param name="width">The terminal width in pixels.</param>
|
||||
/// <param name="height">The terminal height in pixels.</param>
|
||||
/// <param name="bufferSize">The size of the buffer.</param>
|
||||
/// <param name="expectSize">The size of the expect buffer.</param>
|
||||
/// <param name="terminalModeValues">The terminal mode values.</param>
|
||||
/// <returns>
|
||||
/// The created <see cref="ShellStream"/> instance.
|
||||
/// </returns>
|
||||
/// <exception cref="SshConnectionException">Client is not connected.</exception>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The <c>TERM</c> environment variable contains an identifier for the text window's capabilities.
|
||||
/// You can get a detailed list of these capabilities by using the ‘infocmp’ command.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The column/row dimensions override the pixel dimensions(when non-zero). Pixel dimensions refer
|
||||
/// to the drawable area of the window.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public ShellStream CreateShellStream(string terminalName, uint columns, uint rows, uint width, uint height, int bufferSize, int expectSize, IDictionary<TerminalModes, uint> terminalModeValues)
|
||||
{
|
||||
EnsureSessionIsOpen();
|
||||
|
||||
return ServiceFactory.CreateShellStream(Session, terminalName, columns, rows, width, height, terminalModeValues, bufferSize, expectSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace Renci.SshNet.IntegrationTests
|
||||
// if the channel would not be properly closed
|
||||
for (var i = 0; i < connectionInfo.MaxSessions + 1; i++)
|
||||
{
|
||||
using (var stream = client.CreateShellStream("vt220", 20, 20, 20, 20, 0))
|
||||
using (var stream = client.CreateShellStream("vt220", 20, 20, 20, 20, 20))
|
||||
{
|
||||
stream.WriteLine("echo test");
|
||||
stream.ReadLine();
|
||||
|
||||
+4
-1
@@ -22,6 +22,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
private uint _height;
|
||||
private IDictionary<TerminalModes, uint> _terminalModeValues;
|
||||
private int _bufferSize;
|
||||
private int _expectSize;
|
||||
private SshException _channelOpenException;
|
||||
private SshException _actualException;
|
||||
|
||||
@@ -36,6 +37,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_height = (uint) random.Next();
|
||||
_terminalModeValues = new Dictionary<TerminalModes, uint>();
|
||||
_bufferSize = random.Next();
|
||||
_expectSize = _bufferSize;
|
||||
_channelOpenException = new SshException();
|
||||
|
||||
_actualException = null;
|
||||
@@ -95,7 +97,8 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_width,
|
||||
_height,
|
||||
_terminalModeValues,
|
||||
_bufferSize);
|
||||
_bufferSize,
|
||||
_expectSize);
|
||||
Assert.Fail();
|
||||
}
|
||||
catch (SshException ex)
|
||||
|
||||
+4
-1
@@ -22,6 +22,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
private uint _height;
|
||||
private IDictionary<TerminalModes, uint> _terminalModeValues;
|
||||
private int _bufferSize;
|
||||
private int _expectSize;
|
||||
private SshException _actualException;
|
||||
|
||||
private void SetupData()
|
||||
@@ -35,6 +36,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_height = (uint)random.Next();
|
||||
_terminalModeValues = new Dictionary<TerminalModes, uint>();
|
||||
_bufferSize = random.Next();
|
||||
_expectSize = _bufferSize;
|
||||
_actualException = null;
|
||||
}
|
||||
|
||||
@@ -94,7 +96,8 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_width,
|
||||
_height,
|
||||
_terminalModeValues,
|
||||
_bufferSize);
|
||||
_bufferSize,
|
||||
_expectSize);
|
||||
Assert.Fail();
|
||||
}
|
||||
catch (SshException ex)
|
||||
|
||||
+4
-1
@@ -22,6 +22,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
private uint _height;
|
||||
private IDictionary<TerminalModes, uint> _terminalModeValues;
|
||||
private int _bufferSize;
|
||||
private int _expectSize;
|
||||
private SshException _sendPseudoTerminalRequestException;
|
||||
private SshException _actualException;
|
||||
|
||||
@@ -36,6 +37,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_height = (uint) random.Next();
|
||||
_terminalModeValues = new Dictionary<TerminalModes, uint>();
|
||||
_bufferSize = random.Next();
|
||||
_expectSize = _bufferSize;
|
||||
_sendPseudoTerminalRequestException = new SshException();
|
||||
|
||||
_actualException = null;
|
||||
@@ -97,7 +99,8 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_width,
|
||||
_height,
|
||||
_terminalModeValues,
|
||||
_bufferSize);
|
||||
_bufferSize,
|
||||
_expectSize);
|
||||
Assert.Fail();
|
||||
}
|
||||
catch (SshException ex)
|
||||
|
||||
+4
-1
@@ -22,6 +22,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
private uint _height;
|
||||
private IDictionary<TerminalModes, uint> _terminalModeValues;
|
||||
private int _bufferSize;
|
||||
private int _expectSize;
|
||||
private SshException _actualException;
|
||||
|
||||
private void SetupData()
|
||||
@@ -35,6 +36,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_height = (uint) random.Next();
|
||||
_terminalModeValues = new Dictionary<TerminalModes, uint>();
|
||||
_bufferSize = random.Next();
|
||||
_expectSize = _bufferSize;
|
||||
_actualException = null;
|
||||
}
|
||||
|
||||
@@ -97,7 +99,8 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_width,
|
||||
_height,
|
||||
_terminalModeValues,
|
||||
_bufferSize);
|
||||
_bufferSize,
|
||||
_expectSize);
|
||||
Assert.Fail();
|
||||
}
|
||||
catch (SshException ex)
|
||||
|
||||
+4
-1
@@ -22,6 +22,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
private uint _height;
|
||||
private IDictionary<TerminalModes, uint> _terminalModeValues;
|
||||
private int _bufferSize;
|
||||
private int _expectSize;
|
||||
private SshException _sendShellRequestException;
|
||||
private SshException _actualException;
|
||||
|
||||
@@ -36,6 +37,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_height = (uint) random.Next();
|
||||
_terminalModeValues = new Dictionary<TerminalModes, uint>();
|
||||
_bufferSize = random.Next();
|
||||
_expectSize = _bufferSize;
|
||||
_sendShellRequestException = new SshException();
|
||||
_actualException = null;
|
||||
}
|
||||
@@ -99,7 +101,8 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_width,
|
||||
_height,
|
||||
_terminalModeValues,
|
||||
_bufferSize);
|
||||
_bufferSize,
|
||||
_expectSize);
|
||||
Assert.Fail();
|
||||
}
|
||||
catch (SshException ex)
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
private uint _height;
|
||||
private IDictionary<TerminalModes, uint> _terminalModeValues;
|
||||
private int _bufferSize;
|
||||
private int _expectSize;
|
||||
private ShellStream _shellStream;
|
||||
|
||||
private void SetupData()
|
||||
@@ -35,6 +36,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_height = (uint) random.Next();
|
||||
_terminalModeValues = new Dictionary<TerminalModes, uint>();
|
||||
_bufferSize = random.Next();
|
||||
_expectSize = _bufferSize;
|
||||
}
|
||||
|
||||
private void CreateMocks()
|
||||
@@ -97,7 +99,8 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_width,
|
||||
_height,
|
||||
_terminalModeValues,
|
||||
_bufferSize);
|
||||
_bufferSize,
|
||||
_expectSize);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
private uint _heightPixels;
|
||||
private Dictionary<TerminalModes, uint> _terminalModes;
|
||||
private int _bufferSize;
|
||||
private int _expectSize;
|
||||
private Mock<IChannelSession> _channelSessionMock;
|
||||
|
||||
protected override void OnInit()
|
||||
@@ -41,6 +42,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_heightPixels = (uint)random.Next();
|
||||
_terminalModes = new Dictionary<TerminalModes, uint>();
|
||||
_bufferSize = random.Next(100, 500);
|
||||
_expectSize = random.Next(100, _bufferSize);
|
||||
|
||||
_encoding = Encoding.UTF8;
|
||||
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
|
||||
@@ -120,7 +122,8 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_widthPixels,
|
||||
_heightPixels,
|
||||
_terminalModes,
|
||||
_bufferSize);
|
||||
_bufferSize,
|
||||
_expectSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,8 @@ namespace Renci.SshNet.Tests.Classes
|
||||
width: 800,
|
||||
height: 600,
|
||||
terminalModeValues: null,
|
||||
bufferSize: 1024);
|
||||
bufferSize: 1024,
|
||||
expectSize: 2048);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@@ -227,6 +228,22 @@ namespace Renci.SshNet.Tests.Classes
|
||||
Assert.AreEqual("んにちは, Bonjour", _shellStream.Read());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Expect_String_LargeExpect()
|
||||
{
|
||||
_channelSessionStub.Receive(Encoding.UTF8.GetBytes(new string('a', 100)));
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
_channelSessionStub.Receive(Encoding.UTF8.GetBytes(new string('b', 100)));
|
||||
}
|
||||
_channelSessionStub.Receive(Encoding.UTF8.GetBytes("Hello, こんにちは, Bonjour"));
|
||||
_channelSessionStub.Receive(Encoding.UTF8.GetBytes(new string('c', 100)));
|
||||
|
||||
Assert.AreEqual($"{new string('a', 100)}{new string('b', 1000)}Hello, こんにちは, Bonjour", _shellStream.Expect($"{new string('b', 1000)}Hello, こんにちは, Bonjour"));
|
||||
|
||||
Assert.AreEqual($"{new string('c', 100)}", _shellStream.Read());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Expect_Timeout()
|
||||
{
|
||||
|
||||
+4
-1
@@ -23,6 +23,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
private Dictionary<TerminalModes, uint> _terminalModes;
|
||||
private ShellStream _shellStream;
|
||||
private int _bufferSize;
|
||||
private int _expectSize;
|
||||
|
||||
private byte[] _data;
|
||||
private int _offset;
|
||||
@@ -47,6 +48,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_heightPixels = (uint) random.Next();
|
||||
_terminalModes = new Dictionary<TerminalModes, uint>();
|
||||
_bufferSize = random.Next(100, 1000);
|
||||
_expectSize = random.Next(100, _bufferSize);
|
||||
|
||||
_data = CryptoAbstraction.GenerateRandom(_bufferSize - 10);
|
||||
_offset = random.Next(1, 5);
|
||||
@@ -101,7 +103,8 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_widthPixels,
|
||||
_heightPixels,
|
||||
_terminalModes,
|
||||
_bufferSize);
|
||||
_bufferSize,
|
||||
_expectSize);
|
||||
}
|
||||
|
||||
private void Act()
|
||||
|
||||
+4
-1
@@ -24,6 +24,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
private Dictionary<TerminalModes, uint> _terminalModes;
|
||||
private ShellStream _shellStream;
|
||||
private int _bufferSize;
|
||||
private int _expectSize;
|
||||
|
||||
private byte[] _data;
|
||||
private int _offset;
|
||||
@@ -50,6 +51,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_heightPixels = (uint)random.Next();
|
||||
_terminalModes = new Dictionary<TerminalModes, uint>();
|
||||
_bufferSize = random.Next(100, 1000);
|
||||
_expectSize = random.Next(100, _bufferSize);
|
||||
|
||||
_data = CryptoAbstraction.GenerateRandom((_bufferSize * 2) + 10);
|
||||
_offset = 0;
|
||||
@@ -111,7 +113,8 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_widthPixels,
|
||||
_heightPixels,
|
||||
_terminalModes,
|
||||
_bufferSize);
|
||||
_bufferSize,
|
||||
_expectSize);
|
||||
}
|
||||
|
||||
private void Act()
|
||||
|
||||
+4
-1
@@ -23,6 +23,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
private Dictionary<TerminalModes, uint> _terminalModes;
|
||||
private ShellStream _shellStream;
|
||||
private int _bufferSize;
|
||||
private int _expectSize;
|
||||
|
||||
private byte[] _data;
|
||||
private int _offset;
|
||||
@@ -47,6 +48,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_heightPixels = (uint)random.Next();
|
||||
_terminalModes = new Dictionary<TerminalModes, uint>();
|
||||
_bufferSize = random.Next(100, 1000);
|
||||
_expectSize = random.Next(100, _bufferSize);
|
||||
|
||||
_data = CryptoAbstraction.GenerateRandom(_bufferSize);
|
||||
_offset = 0;
|
||||
@@ -101,7 +103,8 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_widthPixels,
|
||||
_heightPixels,
|
||||
_terminalModes,
|
||||
_bufferSize);
|
||||
_bufferSize,
|
||||
_expectSize);
|
||||
}
|
||||
|
||||
private void Act()
|
||||
|
||||
+4
-1
@@ -25,6 +25,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
private Dictionary<TerminalModes, uint> _terminalModes;
|
||||
private ShellStream _shellStream;
|
||||
private int _bufferSize;
|
||||
private int _expectSize;
|
||||
|
||||
private byte[] _data;
|
||||
private int _offset;
|
||||
@@ -49,6 +50,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_heightPixels = (uint)random.Next();
|
||||
_terminalModes = new Dictionary<TerminalModes, uint>();
|
||||
_bufferSize = random.Next(100, 1000);
|
||||
_expectSize = random.Next(100, _bufferSize);
|
||||
|
||||
_data = new byte[0];
|
||||
_offset = 0;
|
||||
@@ -103,7 +105,8 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_widthPixels,
|
||||
_heightPixels,
|
||||
_terminalModes,
|
||||
_bufferSize);
|
||||
_bufferSize,
|
||||
_expectSize);
|
||||
}
|
||||
|
||||
private void Act()
|
||||
|
||||
+4
-1
@@ -23,6 +23,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
private Dictionary<TerminalModes, uint> _terminalModes;
|
||||
private ShellStream _shellStream;
|
||||
private int _bufferSize;
|
||||
private int _expectSize;
|
||||
|
||||
private byte[] _data;
|
||||
private int _offset;
|
||||
@@ -48,6 +49,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_heightPixels = (uint)random.Next();
|
||||
_terminalModes = new Dictionary<TerminalModes, uint>();
|
||||
_bufferSize = random.Next(100, 1000);
|
||||
_expectSize = random.Next(100, _bufferSize);
|
||||
|
||||
_bufferData = CryptoAbstraction.GenerateRandom(_bufferSize);
|
||||
_data = CryptoAbstraction.GenerateRandom(_bufferSize - 10);
|
||||
@@ -105,7 +107,8 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_widthPixels,
|
||||
_heightPixels,
|
||||
_terminalModes,
|
||||
_bufferSize);
|
||||
_bufferSize,
|
||||
_expectSize);
|
||||
|
||||
_shellStream.Write(_bufferData, 0, _bufferData.Length);
|
||||
}
|
||||
|
||||
+4
-1
@@ -23,6 +23,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
private Dictionary<TerminalModes, uint> _terminalModes;
|
||||
private ShellStream _shellStream;
|
||||
private int _bufferSize;
|
||||
private int _expectSize;
|
||||
|
||||
private byte[] _data;
|
||||
private int _offset;
|
||||
@@ -48,6 +49,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_heightPixels = (uint) random.Next();
|
||||
_terminalModes = new Dictionary<TerminalModes, uint>();
|
||||
_bufferSize = random.Next(100, 1000);
|
||||
_expectSize = random.Next(100, _bufferSize);
|
||||
|
||||
_bufferData = CryptoAbstraction.GenerateRandom(_bufferSize);
|
||||
_data = new byte[0];
|
||||
@@ -103,7 +105,8 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_widthPixels,
|
||||
_heightPixels,
|
||||
_terminalModes,
|
||||
_bufferSize);
|
||||
_bufferSize,
|
||||
_expectSize);
|
||||
|
||||
_shellStream.Write(_bufferData, 0, _bufferData.Length);
|
||||
}
|
||||
|
||||
+4
-1
@@ -23,6 +23,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
private Dictionary<TerminalModes, uint> _terminalModes;
|
||||
private ShellStream _shellStream;
|
||||
private int _bufferSize;
|
||||
private int _expectSize;
|
||||
|
||||
private byte[] _data;
|
||||
private int _offset;
|
||||
@@ -48,6 +49,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_heightPixels = (uint) random.Next();
|
||||
_terminalModes = new Dictionary<TerminalModes, uint>();
|
||||
_bufferSize = random.Next(100, 1000);
|
||||
_expectSize = random.Next(100, _bufferSize);
|
||||
|
||||
_bufferData = CryptoAbstraction.GenerateRandom(_bufferSize - 60);
|
||||
_data = CryptoAbstraction.GenerateRandom(_bufferSize + 100);
|
||||
@@ -103,7 +105,8 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_widthPixels,
|
||||
_heightPixels,
|
||||
_terminalModes,
|
||||
_bufferSize);
|
||||
_bufferSize,
|
||||
_expectSize);
|
||||
|
||||
_shellStream.Write(_bufferData, 0, _bufferData.Length);
|
||||
}
|
||||
|
||||
+4
-1
@@ -24,6 +24,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
private Dictionary<TerminalModes, uint> _terminalModes;
|
||||
private ShellStream _shellStream;
|
||||
private int _bufferSize;
|
||||
private int _expectSize;
|
||||
|
||||
private byte[] _data;
|
||||
private int _offset;
|
||||
@@ -50,6 +51,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_heightPixels = (uint) random.Next();
|
||||
_terminalModes = new Dictionary<TerminalModes, uint>();
|
||||
_bufferSize = random.Next(100, 1000);
|
||||
_expectSize = random.Next(100, _bufferSize);
|
||||
|
||||
_bufferData = CryptoAbstraction.GenerateRandom(_bufferSize - 60);
|
||||
_data = CryptoAbstraction.GenerateRandom(_bufferSize - _bufferData.Length + random.Next(1, 10));
|
||||
@@ -111,7 +113,8 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_widthPixels,
|
||||
_heightPixels,
|
||||
_terminalModes,
|
||||
_bufferSize);
|
||||
_bufferSize,
|
||||
_expectSize);
|
||||
|
||||
_shellStream.Write(_bufferData, 0, _bufferData.Length);
|
||||
}
|
||||
|
||||
+4
-1
@@ -23,6 +23,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
private Dictionary<TerminalModes, uint> _terminalModes;
|
||||
private ShellStream _shellStream;
|
||||
private int _bufferSize;
|
||||
private int _expectSize;
|
||||
|
||||
private byte[] _data;
|
||||
private int _offset;
|
||||
@@ -48,6 +49,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_heightPixels = (uint)random.Next();
|
||||
_terminalModes = new Dictionary<TerminalModes, uint>();
|
||||
_bufferSize = random.Next(100, 1000);
|
||||
_expectSize = random.Next(100, _bufferSize);
|
||||
|
||||
_bufferData = CryptoAbstraction.GenerateRandom(_bufferSize - 60);
|
||||
_data = new byte[0];
|
||||
@@ -103,7 +105,8 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_widthPixels,
|
||||
_heightPixels,
|
||||
_terminalModes,
|
||||
_bufferSize);
|
||||
_bufferSize,
|
||||
_expectSize);
|
||||
|
||||
_shellStream.Write(_bufferData, 0, _bufferData.Length);
|
||||
}
|
||||
|
||||
+8
-2
@@ -19,6 +19,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
private uint _heightPixels;
|
||||
private Dictionary<TerminalModes, uint> _terminalModes;
|
||||
private int _bufferSize;
|
||||
private int _expectSize;
|
||||
private ShellStream _expected;
|
||||
private ShellStream _actual;
|
||||
|
||||
@@ -35,6 +36,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_heightPixels = (uint) random.Next();
|
||||
_terminalModes = new Dictionary<TerminalModes, uint>();
|
||||
_bufferSize = random.Next(100, 1000);
|
||||
_expectSize = random.Next(100, _bufferSize);
|
||||
|
||||
_expected = CreateShellStream();
|
||||
}
|
||||
@@ -59,7 +61,8 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_widthPixels,
|
||||
_heightPixels,
|
||||
_terminalModes,
|
||||
_bufferSize))
|
||||
_bufferSize,
|
||||
_expectSize))
|
||||
.Returns(_expected);
|
||||
}
|
||||
|
||||
@@ -79,6 +82,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_widthPixels,
|
||||
_heightPixels,
|
||||
_bufferSize,
|
||||
_expectSize,
|
||||
_terminalModes);
|
||||
}
|
||||
|
||||
@@ -92,7 +96,8 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_widthPixels,
|
||||
_heightPixels,
|
||||
_terminalModes,
|
||||
_bufferSize),
|
||||
_bufferSize,
|
||||
_expectSize),
|
||||
Times.Once);
|
||||
}
|
||||
|
||||
@@ -130,6 +135,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_widthPixels,
|
||||
_heightPixels,
|
||||
_terminalModes,
|
||||
1,
|
||||
1);
|
||||
}
|
||||
}
|
||||
|
||||
+9
-3
@@ -19,6 +19,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
private uint _widthPixels;
|
||||
private uint _heightPixels;
|
||||
private int _bufferSize;
|
||||
private int _expectSize;
|
||||
private ShellStream _expected;
|
||||
private ShellStream _actual;
|
||||
|
||||
@@ -34,6 +35,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_widthPixels = (uint)random.Next();
|
||||
_heightPixels = (uint)random.Next();
|
||||
_bufferSize = random.Next(100, 1000);
|
||||
_expectSize = random.Next(100, _bufferSize);
|
||||
|
||||
_expected = CreateShellStream();
|
||||
}
|
||||
@@ -58,7 +60,8 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_widthPixels,
|
||||
_heightPixels,
|
||||
null,
|
||||
_bufferSize))
|
||||
_bufferSize,
|
||||
_expectSize))
|
||||
.Returns(_expected);
|
||||
}
|
||||
|
||||
@@ -77,7 +80,8 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_heightRows,
|
||||
_widthPixels,
|
||||
_heightPixels,
|
||||
_bufferSize);
|
||||
_bufferSize,
|
||||
_expectSize);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@@ -90,7 +94,8 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_widthPixels,
|
||||
_heightPixels,
|
||||
null,
|
||||
_bufferSize),
|
||||
_bufferSize,
|
||||
_expectSize),
|
||||
Times.Once);
|
||||
}
|
||||
|
||||
@@ -128,6 +133,7 @@ namespace Renci.SshNet.Tests.Classes
|
||||
_widthPixels,
|
||||
_heightPixels,
|
||||
null,
|
||||
1,
|
||||
1);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user