Pass buffer size to ShellStream ctor.

Fixes issue #303.

Added tests for issue #303 and PR #211.
This commit is contained in:
Gert Driesen
2017-09-17 17:34:37 +02:00
parent 985e3f3703
commit c3d43b67ec
19 changed files with 1822 additions and 19 deletions
@@ -912,6 +912,9 @@
<Compile Include="..\Renci.SshNet.Tests\Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsZero.cs">
<Link>Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsZero.cs</Link>
</Compile>
<Compile Include="..\Renci.SshNet.Tests\Classes\ServiceFactoryTest_CreateShellStream.cs">
<Link>Classes\ServiceFactoryTest_CreateShellStream.cs</Link>
</Compile>
<Compile Include="..\Renci.SshNet.Tests\Classes\SessionTest.cs">
<Link>Classes\SessionTest.cs</Link>
</Compile>
@@ -1425,12 +1428,45 @@
<Compile Include="..\Renci.SshNet.Tests\Classes\ShellStreamTest.cs">
<Link>Classes\ShellStreamTest.cs</Link>
</Compile>
<Compile Include="..\Renci.SshNet.Tests\Classes\ShellStreamTest_Write_WriteBufferEmptyAndWriteLessBytesThanBufferSize.cs">
<Link>Classes\ShellStreamTest_Write_WriteBufferEmptyAndWriteLessBytesThanBufferSize.cs</Link>
</Compile>
<Compile Include="..\Renci.SshNet.Tests\Classes\ShellStreamTest_Write_WriteBufferEmptyAndWriteMoreBytesThanBufferSize.cs">
<Link>Classes\ShellStreamTest_Write_WriteBufferEmptyAndWriteMoreBytesThanBufferSize.cs</Link>
</Compile>
<Compile Include="..\Renci.SshNet.Tests\Classes\ShellStreamTest_Write_WriteBufferEmptyAndWriteNumberOfBytesEqualToBufferSize.cs">
<Link>Classes\ShellStreamTest_Write_WriteBufferEmptyAndWriteNumberOfBytesEqualToBufferSize.cs</Link>
</Compile>
<Compile Include="..\Renci.SshNet.Tests\Classes\ShellStreamTest_Write_WriteBufferEmptyAndWriteZeroBytes.cs">
<Link>Classes\ShellStreamTest_Write_WriteBufferEmptyAndWriteZeroBytes.cs</Link>
</Compile>
<Compile Include="..\Renci.SshNet.Tests\Classes\ShellStreamTest_Write_WriteBufferFullAndWriteLessBytesThanBufferSize.cs">
<Link>Classes\ShellStreamTest_Write_WriteBufferFullAndWriteLessBytesThanBufferSize.cs</Link>
</Compile>
<Compile Include="..\Renci.SshNet.Tests\Classes\ShellStreamTest_Write_WriteBufferFullAndWriteZeroBytes.cs">
<Link>Classes\ShellStreamTest_Write_WriteBufferFullAndWriteZeroBytes.cs</Link>
</Compile>
<Compile Include="..\Renci.SshNet.Tests\Classes\ShellStreamTest_Write_WriteBufferNotEmptyAndWriteLessBytesThanBufferCanContain.cs">
<Link>Classes\ShellStreamTest_Write_WriteBufferNotEmptyAndWriteLessBytesThanBufferCanContain.cs</Link>
</Compile>
<Compile Include="..\Renci.SshNet.Tests\Classes\ShellStreamTest_Write_WriteBufferNotEmptyAndWriteMoreBytesThanBufferCanContain.cs">
<Link>Classes\ShellStreamTest_Write_WriteBufferNotEmptyAndWriteMoreBytesThanBufferCanContain.cs</Link>
</Compile>
<Compile Include="..\Renci.SshNet.Tests\Classes\ShellStreamTest_Write_WriteBufferNotEmptyAndWriteZeroBytes.cs">
<Link>Classes\ShellStreamTest_Write_WriteBufferNotEmptyAndWriteZeroBytes.cs</Link>
</Compile>
<Compile Include="..\Renci.SshNet.Tests\Classes\ShellTestTest.cs">
<Link>Classes\ShellTestTest.cs</Link>
</Compile>
<Compile Include="..\Renci.SshNet.Tests\Classes\SshClientTest.cs">
<Link>Classes\SshClientTest.cs</Link>
</Compile>
<Compile Include="..\Renci.SshNet.Tests\Classes\SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSizeAndTerminalModes_Connected.cs">
<Link>Classes\SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSizeAndTerminalModes_Connected.cs</Link>
</Compile>
<Compile Include="..\Renci.SshNet.Tests\Classes\SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSize_Connected.cs">
<Link>Classes\SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSize_Connected.cs</Link>
</Compile>
<Compile Include="..\Renci.SshNet.Tests\Classes\SshClientTest_Disconnect_ForwardedPortStarted.cs">
<Link>Classes\SshClientTest_Disconnect_ForwardedPortStarted.cs</Link>
</Compile>
@@ -1632,7 +1668,7 @@
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
<UserProperties ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" ProjectLinkReference="c45379b9-17b1-4e89-bc2e-6d41726413e8" />
<UserProperties ProjectLinkReference="c45379b9-17b1-4e89-bc2e-6d41726413e8" ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" />
</VisualStudio>
</ProjectExtensions>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
@@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Channels;
using Renci.SshNet.Common;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class ServiceFactoryTest_CreateShellStream
{
private Mock<ISession> _sessionMock;
private Mock<IConnectionInfo> _connectionInfoMock;
private Mock<IChannelSession> _channelSessionMock;
private MockSequence _mockSequence;
private ServiceFactory _serviceFactory;
private string _terminalName;
private uint _columns;
private uint _rows;
private uint _width;
private uint _height;
private IDictionary<TerminalModes, uint> _terminalModeValues;
private int _bufferSize;
private ShellStream _shellStream;
private void SetupData()
{
var random = new Random();
_terminalName = random.Next().ToString();
_columns = (uint) random.Next();
_rows = (uint) random.Next();
_width = (uint) random.Next();
_height = (uint) random.Next();
_terminalModeValues = new Dictionary<TerminalModes, uint>();
_bufferSize = random.Next();
}
private void CreateMocks()
{
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
_connectionInfoMock = new Mock<IConnectionInfo>(MockBehavior.Strict);
_channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
}
private void SetupMocks()
{
_mockSequence = new MockSequence();
_sessionMock.InSequence(_mockSequence)
.Setup(p => p.ConnectionInfo)
.Returns(_connectionInfoMock.Object);
_connectionInfoMock.InSequence(_mockSequence)
.Setup(p => p.Encoding)
.Returns(new UTF8Encoding());
_sessionMock.InSequence(_mockSequence)
.Setup(p => p.CreateChannelSession())
.Returns(_channelSessionMock.Object);
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.Open());
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendPseudoTerminalRequest(_terminalName,
_columns,
_rows,
_width,
_height,
_terminalModeValues))
.Returns(true);
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendShellRequest())
.Returns(true);
}
private void Arrange()
{
SetupData();
CreateMocks();
SetupMocks();
_serviceFactory = new ServiceFactory();
}
[TestInitialize]
public void Initialize()
{
Arrange();
Act();
}
private void Act()
{
_shellStream = _serviceFactory.CreateShellStream(_sessionMock.Object,
_terminalName,
_columns,
_rows,
_width,
_height,
_terminalModeValues,
_bufferSize);
}
[TestMethod]
public void CreateShellStreamShouldNotReturnNull()
{
Assert.IsNotNull(_shellStream);
}
[TestMethod]
public void BufferSizeOfShellStreamShouldBeValuePassedToCreateShellStream()
{
Assert.AreEqual(_bufferSize, _shellStream.BufferSize);
}
[TestMethod]
public void SendPseudoTerminalRequestShouldHaveBeenInvokedOnce()
{
_channelSessionMock.Verify(p => p.SendPseudoTerminalRequest(_terminalName,
_columns,
_rows,
_width,
_height,
_terminalModeValues),
Times.Once);
}
[TestMethod]
public void SendShellRequestShouldHaveBeenInvokedOnce()
{
_channelSessionMock.Verify(p => p.SendShellRequest(), Times.Once);
}
}
}
@@ -26,6 +26,7 @@ namespace Renci.SshNet.Tests.Classes
private uint _widthPixels;
private uint _heightPixels;
private Dictionary<TerminalModes, uint> _terminalModes;
private int _bufferSize;
private Mock<IChannelSession> _channelSessionMock;
protected override void OnInit()
@@ -39,6 +40,7 @@ namespace Renci.SshNet.Tests.Classes
_widthPixels = (uint)random.Next();
_heightPixels = (uint)random.Next();
_terminalModes = new Dictionary<TerminalModes, uint>();
_bufferSize = random.Next(100, 500);
_encoding = Encoding.UTF8;
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
@@ -111,8 +113,14 @@ namespace Renci.SshNet.Tests.Classes
_widthPixels, _heightPixels, _terminalModes)).Returns(true);
_channelSessionMock.Setup(p => p.SendShellRequest()).Returns(true);
return new ShellStream(_sessionMock.Object, _terminalName, _widthColumns, _heightRows,
_widthPixels, _heightPixels, _terminalModes);
return new ShellStream(_sessionMock.Object,
_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
_terminalModes,
_bufferSize);
}
}
}
@@ -0,0 +1,135 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Abstractions;
using Renci.SshNet.Channels;
using Renci.SshNet.Common;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class ShellStreamTest_Write_WriteBufferEmptyAndWriteLessBytesThanBufferSize
{
private Mock<ISession> _sessionMock;
private Mock<IConnectionInfo> _connectionInfoMock;
private Mock<IChannelSession> _channelSessionMock;
private string _terminalName;
private uint _widthColumns;
private uint _heightRows;
private uint _widthPixels;
private uint _heightPixels;
private Dictionary<TerminalModes, uint> _terminalModes;
private ShellStream _shellStream;
private int _bufferSize;
private byte[] _data;
private int _offset;
private int _count;
private MockSequence _mockSequence;
[TestInitialize]
public void Initialize()
{
Arrange();
Act();
}
private void SetupData()
{
var random = new Random();
_terminalName = random.Next().ToString();
_widthColumns = (uint) random.Next();
_heightRows = (uint) random.Next();
_widthPixels = (uint) random.Next();
_heightPixels = (uint) random.Next();
_terminalModes = new Dictionary<TerminalModes, uint>();
_bufferSize = random.Next(100, 1000);
_data = CryptoAbstraction.GenerateRandom(_bufferSize - 10);
_offset = random.Next(1, 5);
_count = _data.Length - _offset - random.Next(1, 10);
}
private void CreateMocks()
{
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
_connectionInfoMock = new Mock<IConnectionInfo>(MockBehavior.Strict);
_channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
}
private void SetupMocks()
{
_mockSequence = new MockSequence();
_sessionMock.InSequence(_mockSequence)
.Setup(p => p.ConnectionInfo)
.Returns(_connectionInfoMock.Object);
_connectionInfoMock.InSequence(_mockSequence)
.Setup(p => p.Encoding)
.Returns(new UTF8Encoding());
_sessionMock.InSequence(_mockSequence)
.Setup(p => p.CreateChannelSession())
.Returns(_channelSessionMock.Object);
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.Open());
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendPseudoTerminalRequest(_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
_terminalModes))
.Returns(true);
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendShellRequest())
.Returns(true);
}
private void Arrange()
{
SetupData();
CreateMocks();
SetupMocks();
_shellStream = new ShellStream(_sessionMock.Object,
_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
_terminalModes,
_bufferSize);
}
private void Act()
{
_shellStream.Write(_data, _offset, _count);
}
[TestMethod]
public void NoDataShouldBeSentToServer()
{
_channelSessionMock.Verify(p => p.SendData(It.IsAny<byte[]>()), Times.Never);
}
[TestMethod]
public void FlushShouldSendWrittenBytesToServer()
{
byte[] bytesSent = null;
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendData(It.IsAny<byte[]>()))
.Callback<byte[]>(data => bytesSent = data);
_shellStream.Flush();
Assert.IsNotNull(bytesSent);
Assert.IsTrue(_data.Take(_offset, _count).IsEqualTo(bytesSent));
_channelSessionMock.Verify(p => p.SendData(It.IsAny<byte[]>()), Times.Once);
}
}
}
@@ -0,0 +1,142 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Abstractions;
using Renci.SshNet.Channels;
using Renci.SshNet.Common;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class ShellStreamTest_Write_WriteBufferEmptyAndWriteMoreBytesThanBufferSize
{
private Mock<ISession> _sessionMock;
private Mock<IConnectionInfo> _connectionInfoMock;
private Mock<IChannelSession> _channelSessionMock;
private MockSequence _mockSequence;
private string _terminalName;
private uint _widthColumns;
private uint _heightRows;
private uint _widthPixels;
private uint _heightPixels;
private Dictionary<TerminalModes, uint> _terminalModes;
private ShellStream _shellStream;
private int _bufferSize;
private byte[] _data;
private int _offset;
private int _count;
private byte[] _expectedBytesSent1;
private byte[] _expectedBytesSent2;
[TestInitialize]
public void Initialize()
{
Arrange();
Act();
}
private void SetupData()
{
var random = new Random();
_terminalName = random.Next().ToString();
_widthColumns = (uint)random.Next();
_heightRows = (uint)random.Next();
_widthPixels = (uint)random.Next();
_heightPixels = (uint)random.Next();
_terminalModes = new Dictionary<TerminalModes, uint>();
_bufferSize = random.Next(100, 1000);
_data = CryptoAbstraction.GenerateRandom(_bufferSize * 2 + 10);
_offset = 0;
_count = _data.Length;
_expectedBytesSent1 = _data.Take(0, _bufferSize);
_expectedBytesSent2 = _data.Take(_bufferSize, _bufferSize);
}
private void CreateMocks()
{
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
_connectionInfoMock = new Mock<IConnectionInfo>(MockBehavior.Strict);
_channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
}
private void SetupMocks()
{
_mockSequence = new MockSequence();
_sessionMock.InSequence(_mockSequence)
.Setup(p => p.ConnectionInfo)
.Returns(_connectionInfoMock.Object);
_connectionInfoMock.InSequence(_mockSequence)
.Setup(p => p.Encoding)
.Returns(new UTF8Encoding());
_sessionMock.InSequence(_mockSequence)
.Setup(p => p.CreateChannelSession())
.Returns(_channelSessionMock.Object);
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.Open());
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendPseudoTerminalRequest(_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
_terminalModes))
.Returns(true);
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendShellRequest())
.Returns(true);
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendData(_expectedBytesSent1));
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendData(_expectedBytesSent2));
}
private void Arrange()
{
SetupData();
CreateMocks();
SetupMocks();
_shellStream = new ShellStream(_sessionMock.Object,
_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
_terminalModes,
_bufferSize);
}
private void Act()
{
_shellStream.Write(_data, _offset, _count);
}
[TestMethod]
public void BufferShouldHaveBeenFlushedTwice()
{
_channelSessionMock.Verify(p => p.SendData(_expectedBytesSent1), Times.Once);
_channelSessionMock.Verify(p => p.SendData(_expectedBytesSent2), Times.Once);
}
[TestMethod]
public void FlushShouldSendRemaningBytesToServer()
{
var expectedBytesSent = _data.Take(_bufferSize * 2, _data.Length - _bufferSize * 2);
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendData(expectedBytesSent));
_shellStream.Flush();
_channelSessionMock.Verify(p => p.SendData(expectedBytesSent), Times.Once);
}
}
}
@@ -0,0 +1,129 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Abstractions;
using Renci.SshNet.Channels;
using Renci.SshNet.Common;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class ShellStreamTest_Write_WriteBufferEmptyAndWriteNumberOfBytesEqualToBufferSize
{
private Mock<ISession> _sessionMock;
private Mock<IConnectionInfo> _connectionInfoMock;
private Mock<IChannelSession> _channelSessionMock;
private string _terminalName;
private uint _widthColumns;
private uint _heightRows;
private uint _widthPixels;
private uint _heightPixels;
private Dictionary<TerminalModes, uint> _terminalModes;
private ShellStream _shellStream;
private int _bufferSize;
private byte[] _data;
private int _offset;
private int _count;
private MockSequence _mockSequence;
[TestInitialize]
public void Initialize()
{
Arrange();
Act();
}
private void SetupData()
{
var random = new Random();
_terminalName = random.Next().ToString();
_widthColumns = (uint)random.Next();
_heightRows = (uint)random.Next();
_widthPixels = (uint)random.Next();
_heightPixels = (uint)random.Next();
_terminalModes = new Dictionary<TerminalModes, uint>();
_bufferSize = random.Next(100, 1000);
_data = CryptoAbstraction.GenerateRandom(_bufferSize);
_offset = 0;
_count = _data.Length;
}
private void CreateMocks()
{
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
_connectionInfoMock = new Mock<IConnectionInfo>(MockBehavior.Strict);
_channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
}
private void SetupMocks()
{
_mockSequence = new MockSequence();
_sessionMock.InSequence(_mockSequence)
.Setup(p => p.ConnectionInfo)
.Returns(_connectionInfoMock.Object);
_connectionInfoMock.InSequence(_mockSequence)
.Setup(p => p.Encoding)
.Returns(new UTF8Encoding());
_sessionMock.InSequence(_mockSequence)
.Setup(p => p.CreateChannelSession())
.Returns(_channelSessionMock.Object);
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.Open());
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendPseudoTerminalRequest(_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
_terminalModes))
.Returns(true);
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendShellRequest())
.Returns(true);
}
private void Arrange()
{
SetupData();
CreateMocks();
SetupMocks();
_shellStream = new ShellStream(_sessionMock.Object,
_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
_terminalModes,
_bufferSize);
}
private void Act()
{
_shellStream.Write(_data, _offset, _count);
}
[TestMethod]
public void NoDataShouldBeSentToServer()
{
_channelSessionMock.Verify(p => p.SendData(It.IsAny<byte[]>()), Times.Never);
}
[TestMethod]
public void FlushShouldSendWrittenBytesToServer()
{
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendData(_data));
_shellStream.Flush();
_channelSessionMock.Verify(p => p.SendData(_data), Times.Once);
}
}
}
@@ -0,0 +1,126 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Abstractions;
using Renci.SshNet.Channels;
using Renci.SshNet.Common;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class ShellStreamTest_Write_WriteBufferEmptyAndWriteZeroBytes
{
private Mock<ISession> _sessionMock;
private Mock<IConnectionInfo> _connectionInfoMock;
private Mock<IChannelSession> _channelSessionMock;
private string _terminalName;
private uint _widthColumns;
private uint _heightRows;
private uint _widthPixels;
private uint _heightPixels;
private Dictionary<TerminalModes, uint> _terminalModes;
private ShellStream _shellStream;
private int _bufferSize;
private byte[] _data;
private int _offset;
private int _count;
private MockSequence _mockSequence;
[TestInitialize]
public void Initialize()
{
Arrange();
Act();
}
private void SetupData()
{
var random = new Random();
_terminalName = random.Next().ToString();
_widthColumns = (uint)random.Next();
_heightRows = (uint)random.Next();
_widthPixels = (uint)random.Next();
_heightPixels = (uint)random.Next();
_terminalModes = new Dictionary<TerminalModes, uint>();
_bufferSize = random.Next(100, 1000);
_data = new byte[0];
_offset = 0;
_count = _data.Length;
}
private void CreateMocks()
{
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
_connectionInfoMock = new Mock<IConnectionInfo>(MockBehavior.Strict);
_channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
}
private void SetupMocks()
{
_mockSequence = new MockSequence();
_sessionMock.InSequence(_mockSequence)
.Setup(p => p.ConnectionInfo)
.Returns(_connectionInfoMock.Object);
_connectionInfoMock.InSequence(_mockSequence)
.Setup(p => p.Encoding)
.Returns(new UTF8Encoding());
_sessionMock.InSequence(_mockSequence)
.Setup(p => p.CreateChannelSession())
.Returns(_channelSessionMock.Object);
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.Open());
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendPseudoTerminalRequest(_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
_terminalModes))
.Returns(true);
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendShellRequest())
.Returns(true);
}
private void Arrange()
{
SetupData();
CreateMocks();
SetupMocks();
_shellStream = new ShellStream(_sessionMock.Object,
_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
_terminalModes,
_bufferSize);
}
private void Act()
{
_shellStream.Write(_data, _offset, _count);
}
[TestMethod]
public void NoDataShouldBeSentToServer()
{
_channelSessionMock.Verify(p => p.SendData(It.IsAny<byte[]>()), Times.Never);
}
[TestMethod]
public void FlushShouldSendNoBytesToServer()
{
_shellStream.Flush();
_channelSessionMock.Verify(p => p.SendData(It.IsAny<byte[]>()), Times.Never);
}
}
}
@@ -0,0 +1,135 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Abstractions;
using Renci.SshNet.Channels;
using Renci.SshNet.Common;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class ShellStreamTest_Write_WriteBufferFullAndWriteLessBytesThanBufferSize
{
private Mock<ISession> _sessionMock;
private Mock<IConnectionInfo> _connectionInfoMock;
private Mock<IChannelSession> _channelSessionMock;
private string _terminalName;
private uint _widthColumns;
private uint _heightRows;
private uint _widthPixels;
private uint _heightPixels;
private Dictionary<TerminalModes, uint> _terminalModes;
private ShellStream _shellStream;
private int _bufferSize;
private byte[] _data;
private int _offset;
private int _count;
private MockSequence _mockSequence;
private byte[] _bufferData;
[TestInitialize]
public void Initialize()
{
Arrange();
Act();
}
private void SetupData()
{
var random = new Random();
_terminalName = random.Next().ToString();
_widthColumns = (uint)random.Next();
_heightRows = (uint)random.Next();
_widthPixels = (uint)random.Next();
_heightPixels = (uint)random.Next();
_terminalModes = new Dictionary<TerminalModes, uint>();
_bufferSize = random.Next(100, 1000);
_bufferData = CryptoAbstraction.GenerateRandom(_bufferSize);
_data = CryptoAbstraction.GenerateRandom(_bufferSize - 10);
_offset = 0;
_count = _data.Length;
}
private void CreateMocks()
{
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
_connectionInfoMock = new Mock<IConnectionInfo>(MockBehavior.Strict);
_channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
}
private void SetupMocks()
{
_mockSequence = new MockSequence();
_sessionMock.InSequence(_mockSequence)
.Setup(p => p.ConnectionInfo)
.Returns(_connectionInfoMock.Object);
_connectionInfoMock.InSequence(_mockSequence)
.Setup(p => p.Encoding)
.Returns(new UTF8Encoding());
_sessionMock.InSequence(_mockSequence)
.Setup(p => p.CreateChannelSession())
.Returns(_channelSessionMock.Object);
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.Open());
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendPseudoTerminalRequest(_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
_terminalModes))
.Returns(true);
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendShellRequest())
.Returns(true);
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendData(_bufferData));
}
private void Arrange()
{
SetupData();
CreateMocks();
SetupMocks();
_shellStream = new ShellStream(_sessionMock.Object,
_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
_terminalModes,
_bufferSize);
_shellStream.Write(_bufferData, 0, _bufferData.Length);
}
private void Act()
{
_shellStream.Write(_data, _offset, _count);
}
[TestMethod]
public void BufferShouldBeSentToServer()
{
_channelSessionMock.Verify(p => p.SendData(_bufferData), Times.Once);
}
[TestMethod]
public void FlushShouldSendRemainingBytesInBufferToServer()
{
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendData(_data));
_shellStream.Flush();
_channelSessionMock.Verify(p => p.SendData(_data), Times.Once);
}
}
}
@@ -0,0 +1,133 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Abstractions;
using Renci.SshNet.Channels;
using Renci.SshNet.Common;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class ShellStreamTest_Write_WriteBufferFullAndWriteZeroBytes
{
private Mock<ISession> _sessionMock;
private Mock<IConnectionInfo> _connectionInfoMock;
private Mock<IChannelSession> _channelSessionMock;
private string _terminalName;
private uint _widthColumns;
private uint _heightRows;
private uint _widthPixels;
private uint _heightPixels;
private Dictionary<TerminalModes, uint> _terminalModes;
private ShellStream _shellStream;
private int _bufferSize;
private byte[] _data;
private int _offset;
private int _count;
private MockSequence _mockSequence;
private byte[] _bufferData;
[TestInitialize]
public void Initialize()
{
Arrange();
Act();
}
private void SetupData()
{
var random = new Random();
_terminalName = random.Next().ToString();
_widthColumns = (uint) random.Next();
_heightRows = (uint) random.Next();
_widthPixels = (uint) random.Next();
_heightPixels = (uint) random.Next();
_terminalModes = new Dictionary<TerminalModes, uint>();
_bufferSize = random.Next(100, 1000);
_bufferData = CryptoAbstraction.GenerateRandom(_bufferSize);
_data = new byte[0];
_offset = 0;
_count = _data.Length;
}
private void CreateMocks()
{
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
_connectionInfoMock = new Mock<IConnectionInfo>(MockBehavior.Strict);
_channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
}
private void SetupMocks()
{
_mockSequence = new MockSequence();
_sessionMock.InSequence(_mockSequence)
.Setup(p => p.ConnectionInfo)
.Returns(_connectionInfoMock.Object);
_connectionInfoMock.InSequence(_mockSequence)
.Setup(p => p.Encoding)
.Returns(new UTF8Encoding());
_sessionMock.InSequence(_mockSequence)
.Setup(p => p.CreateChannelSession())
.Returns(_channelSessionMock.Object);
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.Open());
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendPseudoTerminalRequest(_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
_terminalModes))
.Returns(true);
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendShellRequest())
.Returns(true);
}
private void Arrange()
{
SetupData();
CreateMocks();
SetupMocks();
_shellStream = new ShellStream(_sessionMock.Object,
_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
_terminalModes,
_bufferSize);
_shellStream.Write(_bufferData, 0, _bufferData.Length);
}
private void Act()
{
_shellStream.Write(_data, _offset, _count);
}
[TestMethod]
public void NoDataShouldBeSentToServer()
{
_channelSessionMock.Verify(p => p.SendData(It.IsAny<byte[]>()), Times.Never);
}
[TestMethod]
public void FlushShouldSendBufferToServer()
{
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendData(_bufferData));
_shellStream.Flush();
_channelSessionMock.Verify(p => p.SendData(_bufferData), Times.Once);
}
}
}
@@ -0,0 +1,141 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Abstractions;
using Renci.SshNet.Channels;
using Renci.SshNet.Common;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class ShellStreamTest_Write_WriteBufferNotEmptyAndWriteLessBytesThanBufferCanContain
{
private Mock<ISession> _sessionMock;
private Mock<IConnectionInfo> _connectionInfoMock;
private Mock<IChannelSession> _channelSessionMock;
private string _terminalName;
private uint _widthColumns;
private uint _heightRows;
private uint _widthPixels;
private uint _heightPixels;
private Dictionary<TerminalModes, uint> _terminalModes;
private ShellStream _shellStream;
private int _bufferSize;
private byte[] _data;
private int _offset;
private int _count;
private MockSequence _mockSequence;
private byte[] _bufferData;
[TestInitialize]
public void Initialize()
{
Arrange();
Act();
}
private void SetupData()
{
var random = new Random();
_terminalName = random.Next().ToString();
_widthColumns = (uint) random.Next();
_heightRows = (uint) random.Next();
_widthPixels = (uint) random.Next();
_heightPixels = (uint) random.Next();
_terminalModes = new Dictionary<TerminalModes, uint>();
_bufferSize = random.Next(100, 1000);
_bufferData = CryptoAbstraction.GenerateRandom(_bufferSize - 60);
_data = CryptoAbstraction.GenerateRandom(_bufferSize + 100);
_offset = 0;
_count = _bufferSize - _bufferData.Length - random.Next(1, 10);
}
private void CreateMocks()
{
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
_connectionInfoMock = new Mock<IConnectionInfo>(MockBehavior.Strict);
_channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
}
private void SetupMocks()
{
_mockSequence = new MockSequence();
_sessionMock.InSequence(_mockSequence)
.Setup(p => p.ConnectionInfo)
.Returns(_connectionInfoMock.Object);
_connectionInfoMock.InSequence(_mockSequence)
.Setup(p => p.Encoding)
.Returns(new UTF8Encoding());
_sessionMock.InSequence(_mockSequence)
.Setup(p => p.CreateChannelSession())
.Returns(_channelSessionMock.Object);
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.Open());
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendPseudoTerminalRequest(_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
_terminalModes))
.Returns(true);
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendShellRequest())
.Returns(true);
}
private void Arrange()
{
SetupData();
CreateMocks();
SetupMocks();
_shellStream = new ShellStream(_sessionMock.Object,
_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
_terminalModes,
_bufferSize);
_shellStream.Write(_bufferData, 0, _bufferData.Length);
}
private void Act()
{
_shellStream.Write(_data, _offset, _count);
}
[TestMethod]
public void NoDataShouldBeSentToServer()
{
_channelSessionMock.Verify(p => p.SendData(It.IsAny<byte[]>()), Times.Never);
}
[TestMethod]
public void FlushShouldSendWrittenBytesToServer()
{
byte[] bytesSent = null;
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendData(It.IsAny<byte[]>()))
.Callback<byte[]>(data => bytesSent = data);
_shellStream.Flush();
Assert.IsNotNull(bytesSent);
Assert.AreEqual(_bufferData.Length + _count, bytesSent.Length);
Assert.IsTrue(_bufferData.IsEqualTo(bytesSent.Take(_bufferData.Length)));
Assert.IsTrue(_data.Take(0, _count).IsEqualTo(bytesSent.Take(_bufferData.Length, _count)));
_channelSessionMock.Verify(p => p.SendData(It.IsAny<byte[]>()), Times.Once);
}
}
}
@@ -0,0 +1,149 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Abstractions;
using Renci.SshNet.Channels;
using Renci.SshNet.Common;
using Renci.SshNet.Tests.Common;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class ShellStreamTest_Write_WriteBufferNotEmptyAndWriteMoreBytesThanBufferCanContain
{
private Mock<ISession> _sessionMock;
private Mock<IConnectionInfo> _connectionInfoMock;
private Mock<IChannelSession> _channelSessionMock;
private string _terminalName;
private uint _widthColumns;
private uint _heightRows;
private uint _widthPixels;
private uint _heightPixels;
private Dictionary<TerminalModes, uint> _terminalModes;
private ShellStream _shellStream;
private int _bufferSize;
private byte[] _data;
private int _offset;
private int _count;
private MockSequence _mockSequence;
private byte[] _bufferData;
private byte[] _expectedBytesSent;
[TestInitialize]
public void Initialize()
{
Arrange();
Act();
}
private void SetupData()
{
var random = new Random();
_terminalName = random.Next().ToString();
_widthColumns = (uint) random.Next();
_heightRows = (uint) random.Next();
_widthPixels = (uint) random.Next();
_heightPixels = (uint) random.Next();
_terminalModes = new Dictionary<TerminalModes, uint>();
_bufferSize = random.Next(100, 1000);
_bufferData = CryptoAbstraction.GenerateRandom(_bufferSize - 60);
_data = CryptoAbstraction.GenerateRandom(_bufferSize - _bufferData.Length + random.Next(1, 10));
_offset = 0;
_count = _data.Length;
_expectedBytesSent = new ArrayBuilder<byte>().Add(_bufferData)
.Add(_data, 0, _bufferSize - _bufferData.Length)
.Build();
}
private void CreateMocks()
{
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
_connectionInfoMock = new Mock<IConnectionInfo>(MockBehavior.Strict);
_channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
}
private void SetupMocks()
{
_mockSequence = new MockSequence();
_sessionMock.InSequence(_mockSequence)
.Setup(p => p.ConnectionInfo)
.Returns(_connectionInfoMock.Object);
_connectionInfoMock.InSequence(_mockSequence)
.Setup(p => p.Encoding)
.Returns(new UTF8Encoding());
_sessionMock.InSequence(_mockSequence)
.Setup(p => p.CreateChannelSession())
.Returns(_channelSessionMock.Object);
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.Open());
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendPseudoTerminalRequest(_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
_terminalModes))
.Returns(true);
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendShellRequest())
.Returns(true);
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendData(_expectedBytesSent));
}
private void Arrange()
{
SetupData();
CreateMocks();
SetupMocks();
_shellStream = new ShellStream(_sessionMock.Object,
_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
_terminalModes,
_bufferSize);
_shellStream.Write(_bufferData, 0, _bufferData.Length);
}
private void Act()
{
_shellStream.Write(_data, _offset, _count);
}
[TestMethod]
public void BufferShouldBeSentToServer()
{
_channelSessionMock.Verify(p => p.SendData(_expectedBytesSent), Times.Once);
}
[TestMethod]
public void FlushShouldSendRemainingBytesInBufferToServer()
{
var expectedBytesSent = _data.Take(_bufferSize - _bufferData.Length, _data.Length + _bufferData.Length - _bufferSize);
byte[] actualBytesSent = null;
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendData(It.IsAny<byte[]>()))
.Callback<byte[]>(data => actualBytesSent = data);
_shellStream.Flush();
Assert.IsNotNull(actualBytesSent);
Assert.AreEqual(expectedBytesSent.Length, actualBytesSent.Length);
Assert.IsTrue(expectedBytesSent.IsEqualTo(actualBytesSent));
_channelSessionMock.Verify(p => p.SendData(It.IsAny<byte[]>()), Times.Exactly(2));
}
}
}
@@ -0,0 +1,133 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Abstractions;
using Renci.SshNet.Channels;
using Renci.SshNet.Common;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class ShellStreamTest_Write_WriteBufferNotEmptyAndWriteZeroBytes
{
private Mock<ISession> _sessionMock;
private Mock<IConnectionInfo> _connectionInfoMock;
private Mock<IChannelSession> _channelSessionMock;
private string _terminalName;
private uint _widthColumns;
private uint _heightRows;
private uint _widthPixels;
private uint _heightPixels;
private Dictionary<TerminalModes, uint> _terminalModes;
private ShellStream _shellStream;
private int _bufferSize;
private byte[] _data;
private int _offset;
private int _count;
private MockSequence _mockSequence;
private byte[] _bufferData;
[TestInitialize]
public void Initialize()
{
Arrange();
Act();
}
private void SetupData()
{
var random = new Random();
_terminalName = random.Next().ToString();
_widthColumns = (uint)random.Next();
_heightRows = (uint)random.Next();
_widthPixels = (uint)random.Next();
_heightPixels = (uint)random.Next();
_terminalModes = new Dictionary<TerminalModes, uint>();
_bufferSize = random.Next(100, 1000);
_bufferData = CryptoAbstraction.GenerateRandom(_bufferSize - 60);
_data = new byte[0];
_offset = 0;
_count = _data.Length;
}
private void CreateMocks()
{
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
_connectionInfoMock = new Mock<IConnectionInfo>(MockBehavior.Strict);
_channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
}
private void SetupMocks()
{
_mockSequence = new MockSequence();
_sessionMock.InSequence(_mockSequence)
.Setup(p => p.ConnectionInfo)
.Returns(_connectionInfoMock.Object);
_connectionInfoMock.InSequence(_mockSequence)
.Setup(p => p.Encoding)
.Returns(new UTF8Encoding());
_sessionMock.InSequence(_mockSequence)
.Setup(p => p.CreateChannelSession())
.Returns(_channelSessionMock.Object);
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.Open());
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendPseudoTerminalRequest(_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
_terminalModes))
.Returns(true);
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendShellRequest())
.Returns(true);
}
private void Arrange()
{
SetupData();
CreateMocks();
SetupMocks();
_shellStream = new ShellStream(_sessionMock.Object,
_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
_terminalModes,
_bufferSize);
_shellStream.Write(_bufferData, 0, _bufferData.Length);
}
private void Act()
{
_shellStream.Write(_data, _offset, _count);
}
[TestMethod]
public void NoDataShouldBeSentToServer()
{
_channelSessionMock.Verify(p => p.SendData(It.IsAny<byte[]>()), Times.Never);
}
[TestMethod]
public void FlushShouldSendWrittenBytesToServer()
{
_channelSessionMock.InSequence(_mockSequence)
.Setup(p => p.SendData(_bufferData));
_shellStream.Flush();
_channelSessionMock.Verify(p => p.SendData(_bufferData), Times.Once);
}
}
}
@@ -0,0 +1,151 @@
using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Channels;
using Renci.SshNet.Common;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class
SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSizeAndTerminalModes_Connected
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private SshClient _sshClient;
private ConnectionInfo _connectionInfo;
private string _terminalName;
private uint _widthColumns;
private uint _heightRows;
private uint _widthPixels;
private uint _heightPixels;
private Dictionary<TerminalModes, uint> _terminalModes;
private int _bufferSize;
private ShellStream _expected;
private ShellStream _actual;
[TestInitialize]
public void Setup()
{
Arrange();
Act();
}
private void SetupData()
{
var random = new Random();
_connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth"));
_terminalName = random.Next().ToString();
_widthColumns = (uint) random.Next();
_heightRows = (uint) random.Next();
_widthPixels = (uint) random.Next();
_heightPixels = (uint) random.Next();
_terminalModes = new Dictionary<TerminalModes, uint>();
_bufferSize = random.Next(100, 1000);
_expected = CreateShellStream();
}
private void CreateMocks()
{
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
}
private void SetupMocks()
{
var sequence = new MockSequence();
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence)
.Setup(p => p.Connect());
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateShellStream(_sessionMock.Object,
_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
_terminalModes,
_bufferSize))
.Returns(_expected);
}
private void Arrange()
{
SetupData();
CreateMocks();
SetupMocks();
_sshClient = new SshClient(_connectionInfo, false, _serviceFactoryMock.Object);
_sshClient.Connect();
}
protected void Act()
{
_actual = _sshClient.CreateShellStream(_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
_bufferSize,
_terminalModes);
}
[TestMethod]
public void CreateShellStreamOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateShellStream(_sessionMock.Object,
_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
_terminalModes,
_bufferSize),
Times.Once);
}
[TestMethod]
public void CreateShellStreamShouldReturnValueReturnedByCreateShellStreamOnServiceFactory()
{
Assert.IsNotNull(_actual);
Assert.AreSame(_expected, _actual);
}
private ShellStream CreateShellStream()
{
var sessionMock = new Mock<ISession>(MockBehavior.Loose);
var channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
sessionMock.Setup(p => p.ConnectionInfo)
.Returns(new ConnectionInfo("A", "B", new PasswordAuthenticationMethod("A", "B")));
sessionMock.Setup(p => p.CreateChannelSession())
.Returns(channelSessionMock.Object);
channelSessionMock.Setup(p => p.Open());
channelSessionMock.Setup(p => p.SendPseudoTerminalRequest(_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
_terminalModes))
.Returns(true);
channelSessionMock.Setup(p => p.SendShellRequest())
.Returns(true);
return new ShellStream(sessionMock.Object,
_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
_terminalModes,
1);
}
}
}
@@ -0,0 +1,147 @@
using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Channels;
using Renci.SshNet.Common;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSize_Connected
{
private Mock<IServiceFactory> _serviceFactoryMock;
private Mock<ISession> _sessionMock;
private SshClient _sshClient;
private ConnectionInfo _connectionInfo;
private string _terminalName;
private uint _widthColumns;
private uint _heightRows;
private uint _widthPixels;
private uint _heightPixels;
private int _bufferSize;
private ShellStream _expected;
private ShellStream _actual;
[TestInitialize]
public void Setup()
{
Arrange();
Act();
}
private void SetupData()
{
var random = new Random();
_connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth"));
_terminalName = random.Next().ToString();
_widthColumns = (uint)random.Next();
_heightRows = (uint)random.Next();
_widthPixels = (uint)random.Next();
_heightPixels = (uint)random.Next();
_bufferSize = random.Next(100, 1000);
_expected = CreateShellStream();
}
private void CreateMocks()
{
_serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
}
private void SetupMocks()
{
var sequence = new MockSequence();
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateSession(_connectionInfo))
.Returns(_sessionMock.Object);
_sessionMock.InSequence(sequence)
.Setup(p => p.Connect());
_serviceFactoryMock.InSequence(sequence)
.Setup(p => p.CreateShellStream(_sessionMock.Object,
_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
null,
_bufferSize))
.Returns(_expected);
}
private void Arrange()
{
SetupData();
CreateMocks();
SetupMocks();
_sshClient = new SshClient(_connectionInfo, false, _serviceFactoryMock.Object);
_sshClient.Connect();
}
protected void Act()
{
_actual = _sshClient.CreateShellStream(_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
_bufferSize);
}
[TestMethod]
public void CreateShellStreamOnServiceFactoryShouldBeInvokedOnce()
{
_serviceFactoryMock.Verify(p => p.CreateShellStream(_sessionMock.Object,
_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
null,
_bufferSize),
Times.Once);
}
[TestMethod]
public void CreateShellStreamShouldReturnValueReturnedByCreateShellStreamOnServiceFactory()
{
Assert.IsNotNull(_actual);
Assert.AreSame(_expected, _actual);
}
private ShellStream CreateShellStream()
{
var sessionMock = new Mock<ISession>(MockBehavior.Loose);
var channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
sessionMock.Setup(p => p.ConnectionInfo)
.Returns(new ConnectionInfo("A", "B", new PasswordAuthenticationMethod("A", "B")));
sessionMock.Setup(p => p.CreateChannelSession())
.Returns(channelSessionMock.Object);
channelSessionMock.Setup(p => p.Open());
channelSessionMock.Setup(p => p.SendPseudoTerminalRequest(_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
null))
.Returns(true);
channelSessionMock.Setup(p => p.SendShellRequest())
.Returns(true);
return new ShellStream(sessionMock.Object,
_terminalName,
_widthColumns,
_heightRows,
_widthPixels,
_heightPixels,
null,
1);
}
}
}
@@ -270,6 +270,7 @@
<Compile Include="Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsLittleMoreThanFiveTimesGreaterThanChunkSize.cs" />
<Compile Include="Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanTenTimesGreaterThanChunkSize.cs" />
<Compile Include="Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsZero.cs" />
<Compile Include="Classes\ServiceFactoryTest_CreateShellStream.cs" />
<Compile Include="Classes\SessionTest_Connected.cs" />
<Compile Include="Classes\SessionTest_ConnectedBase.cs" />
<Compile Include="Classes\SessionTest_Connected_ConnectionReset.cs" />
@@ -500,9 +501,20 @@
<Compile Include="Classes\Sftp\SftpStatVfsRequestBuilder.cs" />
<Compile Include="Classes\Sftp\SftpStatVfsResponseBuilder.cs" />
<Compile Include="Classes\Sftp\SftpVersionResponseBuilder.cs" />
<Compile Include="Classes\ShellStreamTest_Write_WriteBufferEmptyAndWriteLessBytesThanBufferSize.cs" />
<Compile Include="Classes\ShellStreamTest_Write_WriteBufferEmptyAndWriteMoreBytesThanBufferSize.cs" />
<Compile Include="Classes\ShellStreamTest_Write_WriteBufferEmptyAndWriteNumberOfBytesEqualToBufferSize.cs" />
<Compile Include="Classes\ShellStreamTest_Write_WriteBufferEmptyAndWriteZeroBytes.cs" />
<Compile Include="Classes\ShellStreamTest_Write_WriteBufferFullAndWriteLessBytesThanBufferSize.cs" />
<Compile Include="Classes\ShellStreamTest_Write_WriteBufferFullAndWriteZeroBytes.cs" />
<Compile Include="Classes\ShellStreamTest_Write_WriteBufferNotEmptyAndWriteLessBytesThanBufferCanContain.cs" />
<Compile Include="Classes\ShellStreamTest_Write_WriteBufferNotEmptyAndWriteMoreBytesThanBufferCanContain.cs" />
<Compile Include="Classes\ShellStreamTest_Write_WriteBufferNotEmptyAndWriteZeroBytes.cs" />
<Compile Include="Classes\ShellTestTest.cs" />
<Compile Include="Classes\ShellStreamTest.cs" />
<Compile Include="Classes\SshClientTest.cs" />
<Compile Include="Classes\SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSizeAndTerminalModes_Connected.cs" />
<Compile Include="Classes\SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSize_Connected.cs" />
<Compile Include="Classes\SshClientTest_Disconnect_ForwardedPortStarted.cs" />
<Compile Include="Classes\SshClientTest_Dispose_Connected.cs" />
<Compile Include="Classes\SshClientTest_Dispose_Disconnected.cs" />
+34
View File
@@ -63,6 +63,40 @@ namespace Renci.SshNet
ISftpResponseFactory CreateSftpResponseFactory();
/// <summary>
/// Creates a shell stream.
/// </summary>
/// <param name="session">The SSH session.</param>
/// <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 height in pixels.</param>
/// <param name="height">The terminal height in pixels.</param>
/// <param name="bufferSize">Size of the 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 cababilities 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>
ShellStream CreateShellStream(ISession session,
string terminalName,
uint columns,
uint rows,
uint width,
uint height,
IDictionary<TerminalModes, uint> terminalModeValues,
int bufferSize);
/// <summary>
/// Creates an <see cref="IRemotePathTransformation"/> that encloses a path in double quotes, and escapes
/// any embedded double quote with a backslash.
+30
View File
@@ -139,6 +139,36 @@ namespace Renci.SshNet
return new SftpResponseFactory();
}
/// <summary>
/// Creates a shell stream.
/// </summary>
/// <param name="session">The SSH session.</param>
/// <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 height in pixels.</param>
/// <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>
/// <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 cababilities 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)
{
return new ShellStream(session, terminalName, columns, rows, width, height, terminalModeValues, bufferSize);
}
/// <summary>
/// Creates an <see cref="IRemotePathTransformation"/> that encloses a path in double quotes, and escapes
/// any embedded double quote with a backslash.
+40 -12
View File
@@ -16,10 +16,10 @@ namespace Renci.SshNet
public class ShellStream : Stream
{
private const string CrLf = "\r\n";
private const int BufferSize = 1024;
private readonly ISession _session;
private readonly Encoding _encoding;
private readonly int _bufferSize;
private readonly Queue<byte> _incoming;
private readonly Queue<byte> _outgoing;
private IChannelSession _channel;
@@ -53,10 +53,34 @@ namespace Renci.SshNet
}
}
internal ShellStream(ISession session, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint> terminalModeValues)
/// <summary>
/// Gets the number of bytes that will be written to the internal buffer.
/// </summary>
/// <value>
/// The number of bytes that will be written to the internal buffer.
/// </value>
internal int BufferSize
{
get { return _bufferSize; }
}
/// <summary>
/// Initializes a new <see cref="ShellStream"/> instance.
/// </summary>
/// <param name="session">The SSH session.</param>
/// <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 height in pixels.</param>
/// <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>
internal ShellStream(ISession session, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint> terminalModeValues, int bufferSize)
{
_encoding = session.ConnectionInfo.Encoding;
_session = session;
_bufferSize = bufferSize;
_incoming = new Queue<byte>();
_outgoing = new Queue<byte>();
@@ -110,22 +134,27 @@ namespace Renci.SshNet
/// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.
/// </summary>
/// <exception cref="T:System.IO.IOException">An I/O error occurs.</exception>
/// <exception cref="ObjectDisposedException">Methods were called after the stream was closed.</exception>
public override void Flush()
{
if (_channel == null)
{
throw new ObjectDisposedException("ShellStream");
}
_channel.SendData(_outgoing.ToArray());
_outgoing.Clear();
if (_outgoing.Count > 0)
{
_channel.SendData(_outgoing.ToArray());
_outgoing.Clear();
}
}
/// <summary>
/// Gets the length in bytes of the stream.
/// </summary>
/// <returns>A long value representing the length of the stream in bytes.</returns>
/// <exception cref="T:System.NotSupportedException">A class derived from Stream does not support seeking.</exception>
/// <exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed.</exception>
/// <exception cref="NotSupportedException">A class derived from Stream does not support seeking.</exception>
/// <exception cref="ObjectDisposedException">Methods were called after the stream was closed.</exception>
public override long Length
{
get
@@ -226,13 +255,12 @@ namespace Renci.SshNet
{
foreach (var b in buffer.Take(offset, count))
{
_outgoing.Enqueue(b);
if (_outgoing.Count < BufferSize)
if (_outgoing.Count == _bufferSize)
{
continue;
Flush();
}
Flush();
_outgoing.Enqueue(b);
}
}
@@ -662,9 +690,9 @@ namespace Renci.SshNet
}
/// <summary>
/// Releases the unmanaged resources used by the <see cref="T:System.IO.Stream"/> and optionally releases the managed resources.
/// Releases the unmanaged resources used by the <see cref="Stream"/> and optionally releases the managed resources.
/// </summary>
/// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
+4 -4
View File
@@ -412,7 +412,7 @@ namespace Renci.SshNet
/// <param name="rows">The terminal width in rows.</param>
/// <param name="width">The terminal height in pixels.</param>
/// <param name="height">The terminal height in pixels.</param>
/// <param name="bufferSize">Size of the buffer.</param>
/// <param name="bufferSize">The size of the buffer.</param>
/// <returns>
/// The created <see cref="ShellStream"/> instance.
/// </returns>
@@ -440,7 +440,7 @@ namespace Renci.SshNet
/// <param name="rows">The terminal width in rows.</param>
/// <param name="width">The terminal height in pixels.</param>
/// <param name="height">The terminal height in pixels.</param>
/// <param name="bufferSize">Size of the buffer.</param>
/// <param name="bufferSize">The size of the buffer.</param>
/// <param name="terminalModeValues">The terminal mode values.</param>
/// <returns>
/// The created <see cref="ShellStream"/> instance.
@@ -452,7 +452,7 @@ namespace Renci.SshNet
/// You can get a detailed list of these cababilities by using the infocmp command.
/// </para>
/// <para>
/// The column/row dimensions override the pixel dimensions(when nonzero). Pixel dimensions refer
/// The column/row dimensions override the pixel dimensions(when non-zero). Pixel dimensions refer
/// to the drawable area of the window.
/// </para>
/// </remarks>
@@ -460,7 +460,7 @@ namespace Renci.SshNet
{
EnsureSessionIsOpen();
return new ShellStream(Session, terminalName, columns, rows, width, height, terminalModeValues);
return ServiceFactory.CreateShellStream(Session, terminalName, columns, rows, width, height, terminalModeValues, bufferSize);
}
/// <summary>