2
0

SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsReached.cs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. using System;
  2. using System.Diagnostics;
  3. using System.Threading;
  4. using Microsoft.VisualStudio.TestTools.UnitTesting;
  5. using Moq;
  6. using Renci.SshNet.Common;
  7. using Renci.SshNet.Sftp;
  8. using BufferedRead = Renci.SshNet.Sftp.SftpFileReader.BufferedRead;
  9. namespace Renci.SshNet.Tests.Classes.Sftp
  10. {
  11. [TestClass]
  12. public class SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsReached : SftpFileReaderTestBase
  13. {
  14. private const int ChunkLength = 32 * 1024;
  15. private MockSequence _seq;
  16. private byte[] _handle;
  17. private int _fileSize;
  18. private WaitHandle[] _waitHandleArray;
  19. private int _operationTimeout;
  20. private SftpCloseAsyncResult _closeAsyncResult;
  21. private byte[] _chunk1;
  22. private byte[] _chunk2;
  23. private byte[] _chunk2CatchUp;
  24. private byte[] _chunk3;
  25. private SftpFileReader _reader;
  26. private byte[] _actualChunk1;
  27. private byte[] _actualChunk2;
  28. private byte[] _actualChunk2CatchUp;
  29. private byte[] _actualChunk3;
  30. private ManualResetEvent _chunk1BeginRead;
  31. private ManualResetEvent _chunk2BeginRead;
  32. private ManualResetEvent _chunk3BeginRead;
  33. protected override void SetupData()
  34. {
  35. var random = new Random();
  36. _handle = CreateByteArray(random, 3);
  37. _chunk1 = CreateByteArray(random, ChunkLength);
  38. _chunk2 = CreateByteArray(random, ChunkLength - 10);
  39. _chunk2CatchUp = CreateByteArray(random, 10);
  40. _chunk3 = new byte[0];
  41. _chunk1BeginRead = new ManualResetEvent(false);
  42. _chunk2BeginRead = new ManualResetEvent(false);
  43. _chunk3BeginRead = new ManualResetEvent(false);
  44. _fileSize = _chunk1.Length + _chunk2.Length + _chunk2CatchUp.Length + _chunk3.Length;
  45. _waitHandleArray = new WaitHandle[2];
  46. _operationTimeout = random.Next(10000, 20000);
  47. _closeAsyncResult = new SftpCloseAsyncResult(null, null);
  48. }
  49. protected override void SetupMocks()
  50. {
  51. _seq = new MockSequence();
  52. _ = SftpSessionMock.InSequence(_seq)
  53. .Setup(p => p.CreateWaitHandleArray(It.IsNotNull<WaitHandle>(), It.IsNotNull<WaitHandle>()))
  54. .Returns<WaitHandle, WaitHandle>((disposingWaitHandle, semaphoreAvailableWaitHandle) =>
  55. {
  56. _waitHandleArray[0] = disposingWaitHandle;
  57. _waitHandleArray[1] = semaphoreAvailableWaitHandle;
  58. return _waitHandleArray;
  59. });
  60. _ = SftpSessionMock.InSequence(_seq)
  61. .Setup(p => p.OperationTimeout)
  62. .Returns(_operationTimeout);
  63. _ = SftpSessionMock.InSequence(_seq)
  64. .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
  65. .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
  66. _ = SftpSessionMock.InSequence(_seq)
  67. .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
  68. .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
  69. {
  70. _ = _chunk1BeginRead.Set();
  71. var asyncResult = new SftpReadAsyncResult(callback, state);
  72. asyncResult.SetAsCompleted(_chunk1, false);
  73. })
  74. .Returns((SftpReadAsyncResult)null);
  75. _ = SftpSessionMock.InSequence(_seq)
  76. .Setup(p => p.OperationTimeout)
  77. .Returns(_operationTimeout);
  78. _ = SftpSessionMock.InSequence(_seq)
  79. .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
  80. .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
  81. _ = SftpSessionMock.InSequence(_seq)
  82. .Setup(p => p.BeginRead(_handle, ChunkLength, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
  83. .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
  84. {
  85. _ = _chunk2BeginRead.Set();
  86. var asyncResult = new SftpReadAsyncResult(callback, state);
  87. asyncResult.SetAsCompleted(_chunk2, false);
  88. })
  89. .Returns((SftpReadAsyncResult)null);
  90. _ = SftpSessionMock.InSequence(_seq)
  91. .Setup(p => p.OperationTimeout)
  92. .Returns(_operationTimeout);
  93. _ = SftpSessionMock.InSequence(_seq)
  94. .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
  95. .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
  96. _ = SftpSessionMock.InSequence(_seq)
  97. .Setup(p => p.BeginRead(_handle, 2 * ChunkLength, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
  98. .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
  99. {
  100. _ = _chunk3BeginRead.Set();
  101. var asyncResult = new SftpReadAsyncResult(callback, state);
  102. asyncResult.SetAsCompleted(_chunk3, false);
  103. })
  104. .Returns((SftpReadAsyncResult)null);
  105. _ = SftpSessionMock.InSequence(_seq)
  106. .Setup(p => p.RequestRead(_handle, (2 * ChunkLength) - 10, 10))
  107. .Returns(_chunk2CatchUp);
  108. }
  109. protected override void Arrange()
  110. {
  111. base.Arrange();
  112. _reader = new SftpFileReader(_handle, SftpSessionMock.Object, ChunkLength, 5, _fileSize);
  113. }
  114. protected override void Act()
  115. {
  116. // consume chunk 1
  117. _actualChunk1 = _reader.Read();
  118. // consume chunk 2
  119. _actualChunk2 = _reader.Read();
  120. // wait until chunk3 has been read-ahead
  121. Assert.IsTrue(_chunk3BeginRead.WaitOne(200));
  122. // consume remaining parts of chunk 2
  123. _actualChunk2CatchUp = _reader.Read();
  124. // consume chunk 3
  125. _actualChunk3 = _reader.Read();
  126. }
  127. [TestMethod]
  128. public void FirstReadShouldReturnChunk1()
  129. {
  130. Assert.IsNotNull(_actualChunk1);
  131. Assert.AreSame(_chunk1, _actualChunk1);
  132. }
  133. [TestMethod]
  134. public void SecondReadShouldReturnChunk2()
  135. {
  136. Assert.IsNotNull(_actualChunk2);
  137. Assert.AreSame(_chunk2, _actualChunk2);
  138. }
  139. [TestMethod]
  140. public void ThirdReadShouldReturnChunk2CatchUp()
  141. {
  142. Assert.IsNotNull(_actualChunk2CatchUp);
  143. Assert.AreSame(_chunk2CatchUp, _actualChunk2CatchUp);
  144. }
  145. [TestMethod]
  146. public void FourthReadShouldReturnChunk3()
  147. {
  148. Assert.IsNotNull(_actualChunk3);
  149. Assert.AreSame(_chunk3, _actualChunk3);
  150. }
  151. [TestMethod]
  152. public void ReadAfterEndOfFileShouldThrowSshException()
  153. {
  154. try
  155. {
  156. _ = _reader.Read();
  157. Assert.Fail();
  158. }
  159. catch (SshException ex)
  160. {
  161. Assert.IsNull(ex.InnerException);
  162. Assert.AreEqual("Attempting to read beyond the end of the file.", ex.Message);
  163. }
  164. }
  165. [TestMethod]
  166. public void DisposeShouldCloseHandleAndCompleteImmediately()
  167. {
  168. _ = SftpSessionMock.InSequence(_seq)
  169. .Setup(p => p.IsOpen)
  170. .Returns(true);
  171. _ = SftpSessionMock.InSequence(_seq)
  172. .Setup(p => p.BeginClose(_handle, null, null))
  173. .Returns(_closeAsyncResult);
  174. _ = SftpSessionMock.InSequence(_seq)
  175. .Setup(p => p.EndClose(_closeAsyncResult));
  176. var stopwatch = Stopwatch.StartNew();
  177. _reader.Dispose();
  178. stopwatch.Stop();
  179. Assert.IsTrue(stopwatch.ElapsedMilliseconds < 200, "Dispose took too long to complete: " + stopwatch.ElapsedMilliseconds);
  180. SftpSessionMock.Verify(p => p.IsOpen, Times.Once);
  181. SftpSessionMock.Verify(p => p.BeginClose(_handle, null, null), Times.Once);
  182. SftpSessionMock.Verify(p => p.EndClose(_closeAsyncResult), Times.Once);
  183. }
  184. }
  185. }