Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Take into account the offset in SftpFileStream.Write(byte[] buffer, i…
…nt offset, int count) when not writing to the buffer. Fixes issue #70.
- Loading branch information
Showing
8 changed files
with
271 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
187 changes: 187 additions & 0 deletions
187
.../Sftp/SftpFileStreamTest_Write_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
using System; | ||
using System.Globalization; | ||
using System.IO; | ||
using System.Threading; | ||
using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
using Moq; | ||
using Renci.SshNet.Sftp; | ||
using Renci.SshNet.Sftp.Responses; | ||
|
||
namespace Renci.SshNet.Tests.Classes.Sftp | ||
{ | ||
[TestClass] | ||
public class SftpFileStreamTest_Write_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize | ||
{ | ||
private Mock<ISftpSession> _sftpSessionMock; | ||
private string _path; | ||
private SftpFileStream _sftpFileStream; | ||
private byte[] _handle; | ||
private SftpFileAttributes _fileAttributes; | ||
private uint _bufferSize; | ||
private uint _readBufferSize; | ||
private uint _writeBufferSize; | ||
private byte[] _data; | ||
private int _count; | ||
private int _offset; | ||
private MockSequence _sequence; | ||
private Random _random; | ||
private uint _expectedWrittenByteCount; | ||
private int _expectedBufferedByteCount; | ||
private byte[] _expectedBufferedBytes; | ||
|
||
[TestInitialize] | ||
public void Setup() | ||
{ | ||
Arrange(); | ||
Act(); | ||
} | ||
|
||
[TestCleanup] | ||
public void TearDown() | ||
{ | ||
if (_sftpSessionMock != null) | ||
{ | ||
// allow Dispose to complete successfully | ||
_sftpSessionMock.InSequence(_sequence) | ||
.Setup(p => p.IsOpen) | ||
.Returns(true); | ||
_sftpSessionMock.InSequence(_sequence) | ||
.Setup(p => p.RequestWrite(_handle, _expectedWrittenByteCount, It.IsAny<byte[]>(), 0, _expectedBufferedByteCount, It.IsAny<AutoResetEvent>(), null)); | ||
_sftpSessionMock.InSequence(_sequence) | ||
.Setup(p => p.RequestClose(_handle)); | ||
} | ||
} | ||
|
||
protected void Arrange() | ||
{ | ||
_random = new Random(); | ||
_path = _random.Next().ToString(CultureInfo.InvariantCulture); | ||
_handle = new[] {(byte) _random.Next(byte.MinValue, byte.MaxValue)}; | ||
_fileAttributes = SftpFileAttributes.Empty; | ||
_bufferSize = (uint) _random.Next(1, 1000); | ||
_readBufferSize = (uint) _random.Next(0, 1000); | ||
_writeBufferSize = (uint) _random.Next(500, 1000); | ||
_data = new byte[(_writeBufferSize * 2) + 15]; | ||
_random.NextBytes(_data); | ||
_offset = _random.Next(1, 5); | ||
// to get multiple SSH_FXP_WRITE messages (and verify the offset is updated correctly), we make sure | ||
// the number of bytes to write is at least two times the write buffer size; we write a few extra bytes to | ||
// ensure the buffer is not empty after the writes so we can verify whether Length, Dispose and Flush | ||
// flush the buffer | ||
_count = ((int) _writeBufferSize*2) + _random.Next(1, 5); | ||
|
||
_expectedWrittenByteCount = (2 * _writeBufferSize); | ||
_expectedBufferedByteCount = (int)(_count - _expectedWrittenByteCount); | ||
_expectedBufferedBytes = _data.Take(_offset + (int)_expectedWrittenByteCount, _expectedBufferedByteCount); | ||
|
||
_sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict); | ||
|
||
_sequence = new MockSequence(); | ||
_sftpSessionMock.InSequence(_sequence) | ||
.Setup(p => p.RequestOpen(_path, Flags.Write | Flags.Truncate, true)) | ||
.Returns(_handle); | ||
_sftpSessionMock.InSequence(_sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes); | ||
_sftpSessionMock.InSequence(_sequence) | ||
.Setup(p => p.CalculateOptimalReadLength(_bufferSize)) | ||
.Returns(_readBufferSize); | ||
_sftpSessionMock.InSequence(_sequence) | ||
.Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle)) | ||
.Returns(_writeBufferSize); | ||
_sftpSessionMock.InSequence(_sequence) | ||
.Setup(p => p.IsOpen) | ||
.Returns(true); | ||
_sftpSessionMock.InSequence(_sequence) | ||
.Setup(p => p.RequestWrite(_handle, 0, _data, _offset, (int) _writeBufferSize, It.IsAny<AutoResetEvent>(), null)); | ||
_sftpSessionMock.InSequence(_sequence) | ||
.Setup(p => p.RequestWrite(_handle, _writeBufferSize, _data, _offset + (int) _writeBufferSize, (int)_writeBufferSize, It.IsAny<AutoResetEvent>(), null)); | ||
|
||
_sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.Write, (int) _bufferSize); | ||
} | ||
|
||
protected void Act() | ||
{ | ||
_sftpFileStream.Write(_data, _offset, _count); | ||
} | ||
|
||
[TestMethod] | ||
public void RequestWriteOnSftpSessionShouldBeInvokedTwice() | ||
{ | ||
_sftpSessionMock.Verify(p => p.RequestWrite(_handle, 0, _data, _offset, (int)_writeBufferSize, It.IsAny<AutoResetEvent>(), null), Times.Once); | ||
_sftpSessionMock.Verify(p => p.RequestWrite(_handle, _writeBufferSize, _data, _offset + (int)_writeBufferSize, (int)_writeBufferSize, It.IsAny<AutoResetEvent>(), null), Times.Once); | ||
} | ||
|
||
[TestMethod] | ||
public void PositionShouldBeNumberOfBytesWrittenToFileAndNUmberOfBytesInBuffer() | ||
{ | ||
_sftpSessionMock.InSequence(_sequence) | ||
.Setup(p => p.IsOpen) | ||
.Returns(true); | ||
|
||
Assert.AreEqual(_count, _sftpFileStream.Position); | ||
} | ||
|
||
[TestMethod] | ||
public void LengthShouldFlushBufferAndReturnSizeOfFile() | ||
{ | ||
var lengthFileAttributes = new SftpFileAttributes(DateTime.Now, DateTime.Now, _random.Next(), _random.Next(), | ||
_random.Next(), (uint) _random.Next(0, int.MaxValue), null); | ||
byte[] actualFlushedData = null; | ||
|
||
_sftpSessionMock.InSequence(_sequence) | ||
.Setup(p => p.IsOpen) | ||
.Returns(true); | ||
_sftpSessionMock.InSequence(_sequence) | ||
.Setup(p => p.RequestWrite(_handle, _expectedWrittenByteCount, It.IsAny<byte[]>(), 0, _expectedBufferedByteCount, It.IsAny<AutoResetEvent>(), null)) | ||
.Callback<byte[], ulong, byte[], int, int, AutoResetEvent, Action<SftpStatusResponse>>((handle, serverFileOffset, data, offset, length, wait, writeCompleted) => actualFlushedData = data.Take(offset, length)); | ||
_sftpSessionMock.InSequence(_sequence) | ||
.Setup(p => p.RequestFStat(_handle)) | ||
.Returns(lengthFileAttributes); | ||
|
||
Assert.AreEqual(lengthFileAttributes.Size, _sftpFileStream.Length); | ||
Assert.IsTrue(actualFlushedData.IsEqualTo(_expectedBufferedBytes)); | ||
|
||
_sftpSessionMock.Verify(p => p.RequestWrite(_handle, _expectedWrittenByteCount, It.IsAny<byte[]>(), 0, _expectedBufferedByteCount, It.IsAny<AutoResetEvent>(), null), Times.Once); | ||
} | ||
|
||
[TestMethod] | ||
public void DisposeShouldFlushBufferAndCloseRequest() | ||
{ | ||
byte[] actualFlushedData = null; | ||
|
||
_sftpSessionMock.InSequence(_sequence) | ||
.Setup(p => p.IsOpen) | ||
.Returns(true); | ||
_sftpSessionMock.InSequence(_sequence) | ||
.Setup(p => p.RequestWrite(_handle, _expectedWrittenByteCount, It.IsAny<byte[]>(), 0, _expectedBufferedByteCount, It.IsAny<AutoResetEvent>(), null)) | ||
.Callback<byte[], ulong, byte[], int, int, AutoResetEvent, Action<SftpStatusResponse>>((handle, serverFileOffset, data, offset, length, wait, writeCompleted) => actualFlushedData = data.Take(offset, length)); | ||
_sftpSessionMock.InSequence(_sequence) | ||
.Setup(p => p.RequestClose(_handle)); | ||
|
||
_sftpFileStream.Dispose(); | ||
|
||
Assert.IsTrue(actualFlushedData.IsEqualTo(_expectedBufferedBytes)); | ||
|
||
_sftpSessionMock.Verify(p => p.RequestWrite(_handle, _expectedWrittenByteCount, It.IsAny<byte[]>(), 0, _expectedBufferedByteCount, It.IsAny<AutoResetEvent>(), null), Times.Once); | ||
_sftpSessionMock.Verify(p => p.RequestClose(_handle), Times.Once); | ||
} | ||
|
||
[TestMethod] | ||
public void FlushShouldFlushBuffer() | ||
{ | ||
byte[] actualFlushedData = null; | ||
|
||
_sftpSessionMock.InSequence(_sequence) | ||
.Setup(p => p.IsOpen) | ||
.Returns(true); | ||
_sftpSessionMock.InSequence(_sequence) | ||
.Setup(p => p.RequestWrite(_handle, _expectedWrittenByteCount, It.IsAny<byte[]>(), 0, _expectedBufferedByteCount, It.IsAny<AutoResetEvent>(), null)) | ||
.Callback<byte[], ulong, byte[], int, int, AutoResetEvent, Action<SftpStatusResponse>>((handle, serverFileOffset, data, offset, length, wait, writeCompleted) => actualFlushedData = data.Take(offset, length)); | ||
|
||
_sftpFileStream.Flush(); | ||
|
||
Assert.IsTrue(actualFlushedData.IsEqualTo(_expectedBufferedBytes)); | ||
|
||
_sftpSessionMock.Verify(p => p.RequestWrite(_handle, _expectedWrittenByteCount, It.IsAny<byte[]>(), 0, _expectedBufferedByteCount, It.IsAny<AutoResetEvent>(), null), Times.Once); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.