SftpFileReaderTest_Dispose_SftpSessionIsOpen_EndCloseThrowsException.cs 5.6 KB

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