Skip to content

Commit 664595d

Browse files
Restore the write buffer to ShellStream (#1327)
* Restore Write/Flush tests * Restore write buffer to ShellStream and painfully fix the mocks --------- Co-authored-by: Wojciech Nagórski <[email protected]>
1 parent 59a0f90 commit 664595d

11 files changed

+1351
-109
lines changed

src/Renci.SshNet/ShellStream.cs

Lines changed: 105 additions & 84 deletions
Large diffs are not rendered by default.

test/Renci.SshNet.Tests/Classes/ShellStreamTest.cs

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public void Write_Text_ShouldWriteNothingWhenTextIsNull()
8686

8787
shellStream.Write(text);
8888

89-
_channelSessionMock.Verify(p => p.SendData(It.IsAny<byte[]>()), Times.Never);
89+
_channelSessionMock.VerifyAll();
9090
}
9191

9292
[TestMethod]
@@ -95,33 +95,15 @@ public void WriteLine_Line_ShouldOnlyWriteLineTerminatorWhenLineIsNull()
9595
var shellStream = CreateShellStream();
9696
const string line = null;
9797
var lineTerminator = _encoding.GetBytes("\r");
98-
99-
_channelSessionMock.Setup(p => p.SendData(lineTerminator, 0, lineTerminator.Length));
98+
99+
_ = _channelSessionMock.Setup(p => p.SendData(
100+
It.Is<byte[]>(data => data.Take(lineTerminator.Length).IsEqualTo(lineTerminator)),
101+
0,
102+
lineTerminator.Length));
100103

101104
shellStream.WriteLine(line);
102105

103-
_channelSessionMock.Verify(p => p.SendData(lineTerminator, 0, lineTerminator.Length), Times.Once);
104-
}
105-
106-
[TestMethod]
107-
public void Write_Bytes_SendsToChannel()
108-
{
109-
var shellStream = CreateShellStream();
110-
111-
var bytes1 = _encoding.GetBytes("Hello World!");
112-
var bytes2 = _encoding.GetBytes("Some more bytes!");
113-
114-
_channelSessionMock.Setup(p => p.SendData(bytes1, 0, bytes1.Length));
115-
_channelSessionMock.Setup(p => p.SendData(bytes2, 0, bytes2.Length));
116-
117-
shellStream.Write(bytes1, 0, bytes1.Length);
118-
119-
_channelSessionMock.Verify(p => p.SendData(bytes1, 0, bytes1.Length), Times.Once);
120-
121-
shellStream.Write(bytes2, 0, bytes2.Length);
122-
123-
_channelSessionMock.Verify(p => p.SendData(bytes1, 0, bytes1.Length), Times.Once);
124-
_channelSessionMock.Verify(p => p.SendData(bytes2, 0, bytes2.Length), Times.Once);
106+
_channelSessionMock.VerifyAll();
125107
}
126108

127109
[TestMethod]
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using Microsoft.VisualStudio.TestTools.UnitTesting;
5+
using Moq;
6+
using Renci.SshNet.Abstractions;
7+
using Renci.SshNet.Channels;
8+
using Renci.SshNet.Common;
9+
10+
namespace Renci.SshNet.Tests.Classes
11+
{
12+
[TestClass]
13+
public class ShellStreamTest_Write_WriteBufferEmptyAndWriteLessBytesThanBufferSize
14+
{
15+
private Mock<ISession> _sessionMock;
16+
private Mock<IConnectionInfo> _connectionInfoMock;
17+
private Mock<IChannelSession> _channelSessionMock;
18+
private string _terminalName;
19+
private uint _widthColumns;
20+
private uint _heightRows;
21+
private uint _widthPixels;
22+
private uint _heightPixels;
23+
private Dictionary<TerminalModes, uint> _terminalModes;
24+
private ShellStream _shellStream;
25+
private int _bufferSize;
26+
27+
private byte[] _data;
28+
private int _offset;
29+
private int _count;
30+
private MockSequence _mockSequence;
31+
32+
[TestInitialize]
33+
public void Initialize()
34+
{
35+
Arrange();
36+
Act();
37+
}
38+
39+
private void SetupData()
40+
{
41+
var random = new Random();
42+
43+
_terminalName = random.Next().ToString();
44+
_widthColumns = (uint) random.Next();
45+
_heightRows = (uint) random.Next();
46+
_widthPixels = (uint) random.Next();
47+
_heightPixels = (uint) random.Next();
48+
_terminalModes = new Dictionary<TerminalModes, uint>();
49+
_bufferSize = random.Next(100, 1000);
50+
51+
_data = CryptoAbstraction.GenerateRandom(_bufferSize - 10);
52+
_offset = random.Next(1, 5);
53+
_count = _data.Length - _offset - random.Next(1, 10);
54+
}
55+
56+
private void CreateMocks()
57+
{
58+
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
59+
_connectionInfoMock = new Mock<IConnectionInfo>(MockBehavior.Strict);
60+
_channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
61+
}
62+
63+
private void SetupMocks()
64+
{
65+
_mockSequence = new MockSequence();
66+
67+
_sessionMock.InSequence(_mockSequence)
68+
.Setup(p => p.ConnectionInfo)
69+
.Returns(_connectionInfoMock.Object);
70+
_connectionInfoMock.InSequence(_mockSequence)
71+
.Setup(p => p.Encoding)
72+
.Returns(new UTF8Encoding());
73+
_sessionMock.InSequence(_mockSequence)
74+
.Setup(p => p.CreateChannelSession())
75+
.Returns(_channelSessionMock.Object);
76+
_channelSessionMock.InSequence(_mockSequence)
77+
.Setup(p => p.Open());
78+
_channelSessionMock.InSequence(_mockSequence)
79+
.Setup(p => p.SendPseudoTerminalRequest(_terminalName,
80+
_widthColumns,
81+
_heightRows,
82+
_widthPixels,
83+
_heightPixels,
84+
_terminalModes))
85+
.Returns(true);
86+
_channelSessionMock.InSequence(_mockSequence)
87+
.Setup(p => p.SendShellRequest())
88+
.Returns(true);
89+
}
90+
91+
private void Arrange()
92+
{
93+
SetupData();
94+
CreateMocks();
95+
SetupMocks();
96+
97+
_shellStream = new ShellStream(_sessionMock.Object,
98+
_terminalName,
99+
_widthColumns,
100+
_heightRows,
101+
_widthPixels,
102+
_heightPixels,
103+
_terminalModes,
104+
_bufferSize);
105+
}
106+
107+
private void Act()
108+
{
109+
_shellStream.Write(_data, _offset, _count);
110+
}
111+
112+
[TestMethod]
113+
public void NoDataShouldBeSentToServer()
114+
{
115+
_channelSessionMock.Verify(p => p.SendData(It.IsAny<byte[]>(), It.IsAny<int>(), It.IsAny<int>()), Times.Never);
116+
}
117+
118+
[TestMethod]
119+
public void FlushShouldSendWrittenBytesToServer()
120+
{
121+
byte[] bytesSent = null;
122+
123+
_channelSessionMock.InSequence(_mockSequence)
124+
.Setup(p => p.SendData(It.IsAny<byte[]>(), It.IsAny<int>(), It.IsAny<int>()))
125+
.Callback<byte[], int, int>((data, offset, count) => bytesSent = data.Take(offset, count));
126+
127+
_shellStream.Flush();
128+
129+
Assert.IsNotNull(bytesSent);
130+
Assert.IsTrue(_data.Take(_offset, _count).IsEqualTo(bytesSent));
131+
132+
_channelSessionMock.Verify(p => p.SendData(It.IsAny<byte[]>(), It.IsAny<int>(), It.IsAny<int>()), Times.Once);
133+
}
134+
}
135+
}
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using Microsoft.VisualStudio.TestTools.UnitTesting;
5+
using Moq;
6+
using Renci.SshNet.Abstractions;
7+
using Renci.SshNet.Channels;
8+
using Renci.SshNet.Common;
9+
10+
namespace Renci.SshNet.Tests.Classes
11+
{
12+
[TestClass]
13+
public class ShellStreamTest_Write_WriteBufferEmptyAndWriteMoreBytesThanBufferSize
14+
{
15+
private Mock<ISession> _sessionMock;
16+
private Mock<IConnectionInfo> _connectionInfoMock;
17+
private Mock<IChannelSession> _channelSessionMock;
18+
private MockSequence _mockSequence;
19+
private string _terminalName;
20+
private uint _widthColumns;
21+
private uint _heightRows;
22+
private uint _widthPixels;
23+
private uint _heightPixels;
24+
private Dictionary<TerminalModes, uint> _terminalModes;
25+
private ShellStream _shellStream;
26+
private int _bufferSize;
27+
28+
private byte[] _data;
29+
private int _offset;
30+
private int _count;
31+
32+
private byte[] _expectedBytesSent1;
33+
private byte[] _expectedBytesSent2;
34+
35+
[TestInitialize]
36+
public void Initialize()
37+
{
38+
Arrange();
39+
Act();
40+
}
41+
42+
private void SetupData()
43+
{
44+
var random = new Random();
45+
46+
_terminalName = random.Next().ToString();
47+
_widthColumns = (uint)random.Next();
48+
_heightRows = (uint)random.Next();
49+
_widthPixels = (uint)random.Next();
50+
_heightPixels = (uint)random.Next();
51+
_terminalModes = new Dictionary<TerminalModes, uint>();
52+
_bufferSize = random.Next(100, 1000);
53+
54+
_data = CryptoAbstraction.GenerateRandom((_bufferSize * 2) + 10);
55+
_offset = 0;
56+
_count = _data.Length;
57+
58+
_expectedBytesSent1 = _data.Take(0, _bufferSize);
59+
_expectedBytesSent2 = _data.Take(_bufferSize, _bufferSize);
60+
}
61+
62+
private void CreateMocks()
63+
{
64+
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
65+
_connectionInfoMock = new Mock<IConnectionInfo>(MockBehavior.Strict);
66+
_channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
67+
}
68+
69+
private void SetupMocks()
70+
{
71+
_mockSequence = new MockSequence();
72+
73+
_ = _sessionMock.InSequence(_mockSequence)
74+
.Setup(p => p.ConnectionInfo)
75+
.Returns(_connectionInfoMock.Object);
76+
_ = _connectionInfoMock.InSequence(_mockSequence)
77+
.Setup(p => p.Encoding)
78+
.Returns(new UTF8Encoding());
79+
_ = _sessionMock.InSequence(_mockSequence)
80+
.Setup(p => p.CreateChannelSession())
81+
.Returns(_channelSessionMock.Object);
82+
_ = _channelSessionMock.InSequence(_mockSequence)
83+
.Setup(p => p.Open());
84+
_ = _channelSessionMock.InSequence(_mockSequence)
85+
.Setup(p => p.SendPseudoTerminalRequest(_terminalName,
86+
_widthColumns,
87+
_heightRows,
88+
_widthPixels,
89+
_heightPixels,
90+
_terminalModes))
91+
.Returns(true);
92+
_ = _channelSessionMock.InSequence(_mockSequence)
93+
.Setup(p => p.SendShellRequest())
94+
.Returns(true);
95+
_ = _channelSessionMock.InSequence(_mockSequence)
96+
.Setup(p => p.SendData(_expectedBytesSent1, 0, _bufferSize));
97+
_ = _channelSessionMock.InSequence(_mockSequence)
98+
.Setup(p => p.SendData(_expectedBytesSent2, 0, _bufferSize));
99+
}
100+
101+
private void Arrange()
102+
{
103+
SetupData();
104+
CreateMocks();
105+
SetupMocks();
106+
107+
_shellStream = new ShellStream(_sessionMock.Object,
108+
_terminalName,
109+
_widthColumns,
110+
_heightRows,
111+
_widthPixels,
112+
_heightPixels,
113+
_terminalModes,
114+
_bufferSize);
115+
}
116+
117+
private void Act()
118+
{
119+
_shellStream.Write(_data, _offset, _count);
120+
}
121+
122+
[TestMethod]
123+
public void BufferShouldHaveBeenFlushedTwice()
124+
{
125+
_channelSessionMock.VerifyAll();
126+
}
127+
128+
[TestMethod]
129+
public void FlushShouldSendRemaningBytesToServer()
130+
{
131+
var expectedBytesSent = _data.Take(_bufferSize * 2, _data.Length - (_bufferSize * 2));
132+
133+
_ = _channelSessionMock.InSequence(_mockSequence)
134+
.Setup(p => p.SendData(
135+
It.Is<byte[]>(data => data.Take(expectedBytesSent.Length).IsEqualTo(expectedBytesSent)),
136+
0,
137+
expectedBytesSent.Length));
138+
139+
_shellStream.Flush();
140+
141+
_channelSessionMock.VerifyAll();
142+
}
143+
}
144+
}

0 commit comments

Comments
 (0)