SftpFileStreamTest_WriteAsync_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. using System;
  2. using System.Globalization;
  3. using System.IO;
  4. using System.Threading;
  5. using System.Threading.Tasks;
  6. using Microsoft.VisualStudio.TestTools.UnitTesting;
  7. using Moq;
  8. using Renci.SshNet.Common;
  9. using Renci.SshNet.Sftp;
  10. namespace Renci.SshNet.Tests.Classes.Sftp
  11. {
  12. [TestClass]
  13. public class SftpFileStreamTest_WriteAsync_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize : SftpFileStreamAsyncTestBase
  14. {
  15. private SftpFileStream _target;
  16. private string _path;
  17. private byte[] _handle;
  18. private uint _bufferSize;
  19. private uint _readBufferSize;
  20. private uint _writeBufferSize;
  21. private byte[] _data;
  22. private int _count;
  23. private int _offset;
  24. private Random _random;
  25. private uint _expectedWrittenByteCount;
  26. private int _expectedBufferedByteCount;
  27. private byte[] _expectedBufferedBytes;
  28. private CancellationToken _cancellationToken;
  29. protected override void SetupData()
  30. {
  31. base.SetupData();
  32. _random = new Random();
  33. _path = _random.Next().ToString(CultureInfo.InvariantCulture);
  34. _handle = GenerateRandom(5, _random);
  35. _bufferSize = (uint)_random.Next(1, 1000);
  36. _readBufferSize = (uint)_random.Next(0, 1000);
  37. _writeBufferSize = (uint)_random.Next(500, 1000);
  38. _data = new byte[(_writeBufferSize * 2) + 15];
  39. _random.NextBytes(_data);
  40. _offset = _random.Next(1, 5);
  41. // to get multiple SSH_FXP_WRITE messages (and verify the offset is updated correctly), we make sure
  42. // the number of bytes to write is at least two times the write buffer size; we write a few extra bytes to
  43. // ensure the buffer is not empty after the writes so we can verify whether Length, Dispose and Flush
  44. // flush the buffer
  45. _count = ((int)_writeBufferSize * 2) + _random.Next(1, 5);
  46. _expectedWrittenByteCount = (2 * _writeBufferSize);
  47. _expectedBufferedByteCount = (int)(_count - _expectedWrittenByteCount);
  48. _expectedBufferedBytes = _data.Take(_offset + (int)_expectedWrittenByteCount, _expectedBufferedByteCount);
  49. _cancellationToken = new CancellationToken();
  50. }
  51. protected override void SetupMocks()
  52. {
  53. SftpSessionMock.InSequence(MockSequence)
  54. .Setup(p => p.RequestOpenAsync(_path, Flags.Write | Flags.CreateNewOrOpen | Flags.Truncate, _cancellationToken))
  55. .ReturnsAsync(_handle);
  56. SftpSessionMock.InSequence(MockSequence)
  57. .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
  58. .Returns(_readBufferSize);
  59. SftpSessionMock.InSequence(MockSequence)
  60. .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
  61. .Returns(_writeBufferSize);
  62. SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
  63. SftpSessionMock.InSequence(MockSequence)
  64. .Setup(p => p.RequestWriteAsync(_handle, 0, _data, _offset, (int)_writeBufferSize, _cancellationToken))
  65. .Returns(Task.CompletedTask);
  66. SftpSessionMock.InSequence(MockSequence)
  67. .Setup(p => p.RequestWriteAsync(_handle, _writeBufferSize, _data, _offset + (int)_writeBufferSize, (int)_writeBufferSize, _cancellationToken))
  68. .Returns(Task.CompletedTask);
  69. }
  70. [TestCleanup]
  71. public void TearDown()
  72. {
  73. if (SftpSessionMock != null)
  74. {
  75. // allow Dispose to complete successfully
  76. SftpSessionMock.InSequence(MockSequence)
  77. .Setup(p => p.IsOpen)
  78. .Returns(true);
  79. SftpSessionMock.InSequence(MockSequence)
  80. .Setup(p => p.RequestWriteAsync(_handle, _expectedWrittenByteCount, It.IsAny<byte[]>(), 0, _expectedBufferedByteCount, _cancellationToken))
  81. .Returns(Task.CompletedTask);
  82. SftpSessionMock.InSequence(MockSequence)
  83. .Setup(p => p.RequestClose(_handle));
  84. }
  85. }
  86. protected override async Task ArrangeAsync()
  87. {
  88. await base.ArrangeAsync();
  89. _target = await SftpFileStream.OpenAsync(SftpSessionMock.Object, _path, FileMode.Create, FileAccess.Write, (int)_bufferSize, _cancellationToken);
  90. }
  91. protected override Task ActAsync()
  92. {
  93. return _target.WriteAsync(_data, _offset, _count);
  94. }
  95. [TestMethod]
  96. public void RequestWriteOnSftpSessionShouldBeInvokedTwice()
  97. {
  98. SftpSessionMock.Verify(p => p.RequestWriteAsync(_handle, 0, _data, _offset, (int)_writeBufferSize, _cancellationToken), Times.Once);
  99. SftpSessionMock.Verify(p => p.RequestWriteAsync(_handle, _writeBufferSize, _data, _offset + (int)_writeBufferSize, (int)_writeBufferSize, _cancellationToken), Times.Once);
  100. }
  101. [TestMethod]
  102. public void PositionShouldBeNumberOfBytesWrittenToFileAndNUmberOfBytesInBuffer()
  103. {
  104. SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
  105. Assert.AreEqual(_count, _target.Position);
  106. }
  107. [TestMethod]
  108. public async Task FlushShouldFlushBuffer()
  109. {
  110. byte[] actualFlushedData = null;
  111. SftpSessionMock.InSequence(MockSequence)
  112. .Setup(p => p.IsOpen)
  113. .Returns(true);
  114. SftpSessionMock.InSequence(MockSequence)
  115. .Setup(p => p.RequestWriteAsync(_handle, _expectedWrittenByteCount, It.IsAny<byte[]>(), 0, _expectedBufferedByteCount, _cancellationToken))
  116. .Callback<byte[], ulong, byte[], int, int, CancellationToken>((handle, serverFileOffset, data, offset, length, ct) => actualFlushedData = data.Take(offset, length))
  117. .Returns(Task.CompletedTask);
  118. await _target.FlushAsync();
  119. Assert.IsTrue(actualFlushedData.IsEqualTo(_expectedBufferedBytes));
  120. SftpSessionMock.Verify(p => p.RequestWriteAsync(_handle, _expectedWrittenByteCount, It.IsAny<byte[]>(), 0, _expectedBufferedByteCount, _cancellationToken), Times.Once);
  121. }
  122. }
  123. }