SftpFileReaderTest_Dispose_SftpSessionIsOpen_EndCloseThrowsException.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. using System;
  2. using System.Threading;
  3. using Microsoft.VisualStudio.TestTools.UnitTesting;
  4. using Moq;
  5. #if !FEATURE_EVENTWAITHANDLE_DISPOSE
  6. using Renci.SshNet.Common;
  7. #endif // !FEATURE_EVENTWAITHANDLE_DISPOSE
  8. using Renci.SshNet.Sftp;
  9. using BufferedRead = Renci.SshNet.Sftp.SftpFileReader.BufferedRead;
  10. namespace Renci.SshNet.Tests.Classes.Sftp
  11. {
  12. [TestClass]
  13. public class SftpFileReaderTest_Dispose_SftpSessionIsOpen_EndCloseThrowsException : SftpFileReaderTestBase
  14. {
  15. private const int ChunkLength = 32 * 1024;
  16. private MockSequence _seq;
  17. private byte[] _handle;
  18. private int _fileSize;
  19. private WaitHandle[] _waitHandleArray;
  20. private int _operationTimeout;
  21. private SftpCloseAsyncResult _closeAsyncResult;
  22. private SftpFileReader _reader;
  23. private AsyncCallback _readAsyncCallback;
  24. private ManualResetEvent _beginReadInvoked;
  25. private EventWaitHandle _disposeCompleted;
  26. [TestCleanup]
  27. public void TearDown()
  28. {
  29. _beginReadInvoked?.Dispose();
  30. _disposeCompleted?.Dispose();
  31. }
  32. protected override void SetupData()
  33. {
  34. var random = new Random();
  35. _handle = CreateByteArray(random, 5);
  36. _fileSize = 5000;
  37. _waitHandleArray = new WaitHandle[2];
  38. _operationTimeout = random.Next(10000, 20000);
  39. _closeAsyncResult = new SftpCloseAsyncResult(null, null);
  40. _beginReadInvoked = new ManualResetEvent(false);
  41. _disposeCompleted = new ManualResetEvent(false);
  42. _readAsyncCallback = null;
  43. }
  44. protected override void SetupMocks()
  45. {
  46. _seq = new MockSequence();
  47. _ = SftpSessionMock.InSequence(_seq)
  48. .Setup(p => p.CreateWaitHandleArray(It.IsNotNull<WaitHandle>(), It.IsNotNull<WaitHandle>()))
  49. .Returns<WaitHandle, WaitHandle>((disposingWaitHandle, semaphoreAvailableWaitHandle) =>
  50. {
  51. _waitHandleArray[0] = disposingWaitHandle;
  52. _waitHandleArray[1] = semaphoreAvailableWaitHandle;
  53. return _waitHandleArray;
  54. });
  55. _ = SftpSessionMock.InSequence(_seq)
  56. .Setup(p => p.OperationTimeout)
  57. .Returns(_operationTimeout);
  58. _ = SftpSessionMock.InSequence(_seq)
  59. .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
  60. .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
  61. _ = SftpSessionMock.InSequence(_seq)
  62. .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
  63. .Callback(() =>
  64. {
  65. // harden test by making sure that we've invoked BeginRead before Dispose is invoked
  66. _ = _beginReadInvoked.Set();
  67. })
  68. .Returns<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
  69. {
  70. _readAsyncCallback = callback;
  71. return null;
  72. })
  73. .Callback(() =>
  74. {
  75. // wait until Dispose has been invoked on reader to allow us to harden test, and
  76. // verify whether Dispose will prevent us from entering the read-ahead loop again
  77. _ = _waitHandleArray[0].WaitOne();
  78. });
  79. _ = SftpSessionMock.InSequence(_seq)
  80. .Setup(p => p.IsOpen)
  81. .Returns(true);
  82. _ = SftpSessionMock.InSequence(_seq)
  83. .Setup(p => p.BeginClose(_handle, null, null))
  84. .Returns(_closeAsyncResult);
  85. _ = SftpSessionMock.InSequence(_seq)
  86. .Setup(p => p.EndClose(_closeAsyncResult))
  87. .Throws(new SshException());
  88. }
  89. protected override void Arrange()
  90. {
  91. base.Arrange();
  92. _reader = new SftpFileReader(_handle, SftpSessionMock.Object, ChunkLength, 1, _fileSize);
  93. }
  94. protected override void Act()
  95. {
  96. Assert.IsTrue(_beginReadInvoked.WaitOne(5000));
  97. _reader.Dispose();
  98. }
  99. [TestMethod]
  100. public void ReadAfterDisposeShouldThrowObjectDisposedException()
  101. {
  102. try
  103. {
  104. _ = _reader.Read();
  105. Assert.Fail();
  106. }
  107. catch (ObjectDisposedException ex)
  108. {
  109. Assert.IsNull(ex.InnerException);
  110. Assert.AreEqual(typeof(SftpFileReader).FullName, ex.ObjectName);
  111. }
  112. }
  113. [TestMethod]
  114. public void InvokeOfReadAheadCallbackShouldCompleteImmediately()
  115. {
  116. Assert.IsNotNull(_readAsyncCallback);
  117. _readAsyncCallback(new SftpReadAsyncResult(null, null));
  118. }
  119. [TestMethod]
  120. public void EndCloseOnSftpSessionShouldHaveBeenInvokedOnce()
  121. {
  122. SftpSessionMock.Verify(p => p.EndClose(_closeAsyncResult), Times.Once);
  123. }
  124. }
  125. }