SftpFileReaderTest_Read_ReadAheadExceptionInBeginRead.cs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. using Microsoft.VisualStudio.TestTools.UnitTesting;
  2. using Moq;
  3. using Renci.SshNet.Common;
  4. using Renci.SshNet.Sftp;
  5. using System;
  6. using System.Diagnostics;
  7. using System.Threading;
  8. using BufferedRead = Renci.SshNet.Sftp.SftpFileReader.BufferedRead;
  9. namespace Renci.SshNet.Tests.Classes.Sftp
  10. {
  11. [TestClass]
  12. public class SftpFileReaderTest_Read_ReadAheadExceptionInBeginRead : 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 SftpFileReader _reader;
  24. private ManualResetEvent _readAheadChunk3;
  25. private ManualResetEvent _readChunk3;
  26. private SshException _exception;
  27. private SshException _actualException;
  28. protected override void SetupData()
  29. {
  30. var random = new Random();
  31. _handle = CreateByteArray(random, 5);
  32. _chunk1 = CreateByteArray(random, ChunkLength);
  33. _chunk2 = CreateByteArray(random, ChunkLength);
  34. _fileSize = _chunk1.Length + _chunk2.Length + 1;
  35. _waitHandleArray = new WaitHandle[2];
  36. _operationTimeout = random.Next(10000, 20000);
  37. _closeAsyncResult = new SftpCloseAsyncResult(null, null);
  38. _readAheadChunk3 = new ManualResetEvent(false);
  39. _readChunk3 = new ManualResetEvent(false);
  40. _exception = new SshException();
  41. }
  42. protected override void SetupMocks()
  43. {
  44. _seq = new MockSequence();
  45. SftpSessionMock.InSequence(_seq)
  46. .Setup(p => p.CreateWaitHandleArray(It.IsNotNull<WaitHandle>(), It.IsNotNull<WaitHandle>()))
  47. .Returns<WaitHandle, WaitHandle>((disposingWaitHandle, semaphoreAvailableWaitHandle) =>
  48. {
  49. _waitHandleArray[0] = disposingWaitHandle;
  50. _waitHandleArray[1] = semaphoreAvailableWaitHandle;
  51. return _waitHandleArray;
  52. });
  53. SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
  54. SftpSessionMock.InSequence(_seq)
  55. .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
  56. .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
  57. SftpSessionMock.InSequence(_seq)
  58. .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
  59. .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
  60. {
  61. var asyncResult = new SftpReadAsyncResult(callback, state);
  62. asyncResult.SetAsCompleted(_chunk1, false);
  63. })
  64. .Returns((SftpReadAsyncResult)null);
  65. SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
  66. SftpSessionMock.InSequence(_seq)
  67. .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
  68. .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
  69. SftpSessionMock.InSequence(_seq)
  70. .Setup(p => p.BeginRead(_handle, ChunkLength, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
  71. .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
  72. {
  73. var asyncResult = new SftpReadAsyncResult(callback, state);
  74. asyncResult.SetAsCompleted(_chunk2, false);
  75. })
  76. .Returns((SftpReadAsyncResult)null);
  77. SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).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, 2 * ChunkLength, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
  83. .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
  84. {
  85. _readAheadChunk3.Set();
  86. _readChunk3.WaitOne(TimeSpan.FromSeconds(5));
  87. // sleep a short time to make sure the client is in the blocking wait
  88. Thread.Sleep(500);
  89. })
  90. .Throws(_exception);
  91. }
  92. protected override void Arrange()
  93. {
  94. base.Arrange();
  95. _reader = new SftpFileReader(_handle, SftpSessionMock.Object, ChunkLength, 3, _fileSize);
  96. }
  97. protected override void Act()
  98. {
  99. _reader.Read();
  100. _reader.Read();
  101. // wait until we've the SftpFileReader has starting reading ahead chunk 3
  102. Assert.IsTrue(_readAheadChunk3.WaitOne(TimeSpan.FromSeconds(5)));
  103. // signal that we are about to read chunk 3
  104. _readChunk3.Set();
  105. try
  106. {
  107. _reader.Read();
  108. Assert.Fail();
  109. }
  110. catch (SshException ex)
  111. {
  112. _actualException = ex;
  113. }
  114. }
  115. [TestMethod]
  116. public void ReadOfThirdChunkShouldThrowExceptionThatOccurredInReadAhead()
  117. {
  118. Assert.IsNotNull(_actualException);
  119. Assert.AreSame(_exception, _actualException);
  120. }
  121. [TestMethod]
  122. public void ReadAfterReadAheadExceptionShouldRethrowExceptionThatOccurredInReadAhead()
  123. {
  124. try
  125. {
  126. _reader.Read();
  127. Assert.Fail();
  128. }
  129. catch (SshException ex)
  130. {
  131. Assert.AreSame(_exception, ex);
  132. }
  133. }
  134. [TestMethod]
  135. public void DisposeShouldCloseHandleAndCompleteImmediately()
  136. {
  137. SftpSessionMock.InSequence(_seq).Setup(p => p.IsOpen).Returns(true);
  138. SftpSessionMock.InSequence(_seq).Setup(p => p.BeginClose(_handle, null, null)).Returns(_closeAsyncResult);
  139. SftpSessionMock.InSequence(_seq).Setup(p => p.EndClose(_closeAsyncResult));
  140. var stopwatch = Stopwatch.StartNew();
  141. _reader.Dispose();
  142. stopwatch.Stop();
  143. Assert.IsTrue(stopwatch.ElapsedMilliseconds < 200, "Dispose took too long to complete: " + stopwatch.ElapsedMilliseconds);
  144. SftpSessionMock.Verify(p => p.IsOpen, Times.Once);
  145. SftpSessionMock.Verify(p => p.BeginClose(_handle, null, null), Times.Once);
  146. SftpSessionMock.Verify(p => p.EndClose(_closeAsyncResult), Times.Once);
  147. }
  148. }
  149. }