SftpFileStreamTest_Write_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. using System;
  2. using System.Globalization;
  3. using System.IO;
  4. using System.Threading;
  5. using Microsoft.VisualStudio.TestTools.UnitTesting;
  6. using Moq;
  7. using Renci.SshNet.Sftp;
  8. using Renci.SshNet.Sftp.Responses;
  9. namespace Renci.SshNet.Tests.Classes.Sftp
  10. {
  11. [TestClass]
  12. public class SftpFileStreamTest_Write_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize
  13. {
  14. private Mock<ISftpSession> _sftpSessionMock;
  15. private string _path;
  16. private SftpFileStream _sftpFileStream;
  17. private byte[] _handle;
  18. private SftpFileAttributes _fileAttributes;
  19. private uint _bufferSize;
  20. private uint _readBufferSize;
  21. private uint _writeBufferSize;
  22. private byte[] _data;
  23. private int _count;
  24. private int _offset;
  25. private MockSequence _sequence;
  26. private Random _random;
  27. private uint _expectedWrittenByteCount;
  28. private int _expectedBufferedByteCount;
  29. private byte[] _expectedBufferedBytes;
  30. [TestInitialize]
  31. public void Setup()
  32. {
  33. Arrange();
  34. Act();
  35. }
  36. [TestCleanup]
  37. public void TearDown()
  38. {
  39. if (_sftpSessionMock != null)
  40. {
  41. // allow Dispose to complete successfully
  42. _sftpSessionMock.InSequence(_sequence)
  43. .Setup(p => p.IsOpen)
  44. .Returns(true);
  45. _sftpSessionMock.InSequence(_sequence)
  46. .Setup(p => p.RequestWrite(_handle, _expectedWrittenByteCount, It.IsAny<byte[]>(), 0, _expectedBufferedByteCount, It.IsAny<AutoResetEvent>(), null));
  47. _sftpSessionMock.InSequence(_sequence)
  48. .Setup(p => p.RequestClose(_handle));
  49. }
  50. }
  51. protected void Arrange()
  52. {
  53. _random = new Random();
  54. _path = _random.Next().ToString(CultureInfo.InvariantCulture);
  55. _handle = new[] {(byte) _random.Next(byte.MinValue, byte.MaxValue)};
  56. _fileAttributes = SftpFileAttributes.Empty;
  57. _bufferSize = (uint) _random.Next(1, 1000);
  58. _readBufferSize = (uint) _random.Next(0, 1000);
  59. _writeBufferSize = (uint) _random.Next(500, 1000);
  60. _data = new byte[(_writeBufferSize * 2) + 15];
  61. _random.NextBytes(_data);
  62. _offset = _random.Next(1, 5);
  63. // to get multiple SSH_FXP_WRITE messages (and verify the offset is updated correctly), we make sure
  64. // the number of bytes to write is at least two times the write buffer size; we write a few extra bytes to
  65. // ensure the buffer is not empty after the writes so we can verify whether Length, Dispose and Flush
  66. // flush the buffer
  67. _count = ((int) _writeBufferSize*2) + _random.Next(1, 5);
  68. _expectedWrittenByteCount = (2 * _writeBufferSize);
  69. _expectedBufferedByteCount = (int)(_count - _expectedWrittenByteCount);
  70. _expectedBufferedBytes = _data.Take(_offset + (int)_expectedWrittenByteCount, _expectedBufferedByteCount);
  71. _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
  72. _sequence = new MockSequence();
  73. _sftpSessionMock.InSequence(_sequence)
  74. .Setup(p => p.RequestOpen(_path, Flags.Write | Flags.Truncate, true))
  75. .Returns(_handle);
  76. _sftpSessionMock.InSequence(_sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
  77. _sftpSessionMock.InSequence(_sequence)
  78. .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
  79. .Returns(_readBufferSize);
  80. _sftpSessionMock.InSequence(_sequence)
  81. .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
  82. .Returns(_writeBufferSize);
  83. _sftpSessionMock.InSequence(_sequence)
  84. .Setup(p => p.IsOpen)
  85. .Returns(true);
  86. _sftpSessionMock.InSequence(_sequence)
  87. .Setup(p => p.RequestWrite(_handle, 0, _data, _offset, (int) _writeBufferSize, It.IsAny<AutoResetEvent>(), null));
  88. _sftpSessionMock.InSequence(_sequence)
  89. .Setup(p => p.RequestWrite(_handle, _writeBufferSize, _data, _offset + (int) _writeBufferSize, (int)_writeBufferSize, It.IsAny<AutoResetEvent>(), null));
  90. _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.Write, (int) _bufferSize);
  91. }
  92. protected void Act()
  93. {
  94. _sftpFileStream.Write(_data, _offset, _count);
  95. }
  96. [TestMethod]
  97. public void RequestWriteOnSftpSessionShouldBeInvokedTwice()
  98. {
  99. _sftpSessionMock.Verify(p => p.RequestWrite(_handle, 0, _data, _offset, (int)_writeBufferSize, It.IsAny<AutoResetEvent>(), null), Times.Once);
  100. _sftpSessionMock.Verify(p => p.RequestWrite(_handle, _writeBufferSize, _data, _offset + (int)_writeBufferSize, (int)_writeBufferSize, It.IsAny<AutoResetEvent>(), null), Times.Once);
  101. }
  102. [TestMethod]
  103. public void PositionShouldBeNumberOfBytesWrittenToFileAndNUmberOfBytesInBuffer()
  104. {
  105. _sftpSessionMock.InSequence(_sequence)
  106. .Setup(p => p.IsOpen)
  107. .Returns(true);
  108. Assert.AreEqual(_count, _sftpFileStream.Position);
  109. }
  110. [TestMethod]
  111. public void LengthShouldFlushBufferAndReturnSizeOfFile()
  112. {
  113. var lengthFileAttributes = new SftpFileAttributes(DateTime.Now, DateTime.Now, _random.Next(), _random.Next(),
  114. _random.Next(), (uint) _random.Next(0, int.MaxValue), null);
  115. byte[] actualFlushedData = null;
  116. _sftpSessionMock.InSequence(_sequence)
  117. .Setup(p => p.IsOpen)
  118. .Returns(true);
  119. _sftpSessionMock.InSequence(_sequence)
  120. .Setup(p => p.RequestWrite(_handle, _expectedWrittenByteCount, It.IsAny<byte[]>(), 0, _expectedBufferedByteCount, It.IsAny<AutoResetEvent>(), null))
  121. .Callback<byte[], ulong, byte[], int, int, AutoResetEvent, Action<SftpStatusResponse>>((handle, serverFileOffset, data, offset, length, wait, writeCompleted) => actualFlushedData = data.Take(offset, length));
  122. _sftpSessionMock.InSequence(_sequence)
  123. .Setup(p => p.RequestFStat(_handle))
  124. .Returns(lengthFileAttributes);
  125. Assert.AreEqual(lengthFileAttributes.Size, _sftpFileStream.Length);
  126. Assert.IsTrue(actualFlushedData.IsEqualTo(_expectedBufferedBytes));
  127. _sftpSessionMock.Verify(p => p.RequestWrite(_handle, _expectedWrittenByteCount, It.IsAny<byte[]>(), 0, _expectedBufferedByteCount, It.IsAny<AutoResetEvent>(), null), Times.Once);
  128. }
  129. [TestMethod]
  130. public void DisposeShouldFlushBufferAndCloseRequest()
  131. {
  132. byte[] actualFlushedData = null;
  133. _sftpSessionMock.InSequence(_sequence)
  134. .Setup(p => p.IsOpen)
  135. .Returns(true);
  136. _sftpSessionMock.InSequence(_sequence)
  137. .Setup(p => p.RequestWrite(_handle, _expectedWrittenByteCount, It.IsAny<byte[]>(), 0, _expectedBufferedByteCount, It.IsAny<AutoResetEvent>(), null))
  138. .Callback<byte[], ulong, byte[], int, int, AutoResetEvent, Action<SftpStatusResponse>>((handle, serverFileOffset, data, offset, length, wait, writeCompleted) => actualFlushedData = data.Take(offset, length));
  139. _sftpSessionMock.InSequence(_sequence)
  140. .Setup(p => p.RequestClose(_handle));
  141. _sftpFileStream.Dispose();
  142. Assert.IsTrue(actualFlushedData.IsEqualTo(_expectedBufferedBytes));
  143. _sftpSessionMock.Verify(p => p.RequestWrite(_handle, _expectedWrittenByteCount, It.IsAny<byte[]>(), 0, _expectedBufferedByteCount, It.IsAny<AutoResetEvent>(), null), Times.Once);
  144. _sftpSessionMock.Verify(p => p.RequestClose(_handle), Times.Once);
  145. }
  146. [TestMethod]
  147. public void FlushShouldFlushBuffer()
  148. {
  149. byte[] actualFlushedData = null;
  150. _sftpSessionMock.InSequence(_sequence)
  151. .Setup(p => p.IsOpen)
  152. .Returns(true);
  153. _sftpSessionMock.InSequence(_sequence)
  154. .Setup(p => p.RequestWrite(_handle, _expectedWrittenByteCount, It.IsAny<byte[]>(), 0, _expectedBufferedByteCount, It.IsAny<AutoResetEvent>(), null))
  155. .Callback<byte[], ulong, byte[], int, int, AutoResetEvent, Action<SftpStatusResponse>>((handle, serverFileOffset, data, offset, length, wait, writeCompleted) => actualFlushedData = data.Take(offset, length));
  156. _sftpFileStream.Flush();
  157. Assert.IsTrue(actualFlushedData.IsEqualTo(_expectedBufferedBytes));
  158. _sftpSessionMock.Verify(p => p.RequestWrite(_handle, _expectedWrittenByteCount, It.IsAny<byte[]>(), 0, _expectedBufferedByteCount, It.IsAny<AutoResetEvent>(), null), Times.Once);
  159. }
  160. }
  161. }