Skip to content

Commit

Permalink
Add unit tests for task-based asynchronous API (sshnet#906)
Browse files Browse the repository at this point in the history
* Fix runtime and culture dependant tests.
* Set C# 7.3 in Tests.csproj to limit intellisense's suggestions under different targets
* Add SftpClientTest.*Async
* Add SftpFileStreamTest_OpenAsync_*
* Add SftpFileStreamTest_WriteAsync_*
* Add SftpFileStreamTest_ReadAsync_*
* Align AppVeyor script with Test project target frameworks
  • Loading branch information
IgorMilavec authored Feb 15, 2022
1 parent 37fb864 commit 4dfc126
Show file tree
Hide file tree
Showing 42 changed files with 3,379 additions and 68 deletions.
4 changes: 2 additions & 2 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ build:

test_script:
- cmd: >-
vstest.console /logger:Appveyor src\Renci.SshNet.Tests\bin\Debug\net40\Renci.SshNet.Tests.dll /TestCaseFilter:"TestCategory!=integration&TestCategory!=LongRunning"
vstest.console /logger:Appveyor src\Renci.SshNet.Tests\bin\Debug\net35\Renci.SshNet.Tests.dll /TestCaseFilter:"TestCategory!=integration&TestCategory!=LongRunning"
vstest.console /logger:Appveyor src\Renci.SshNet.Tests\bin\Debug\net35\Renci.SshNet.Tests.dll /TestCaseFilter:"TestCategory!=integration&TestCategory!=LongRunning"
vstest.console /logger:Appveyor src\Renci.SshNet.Tests\bin\Debug\net472\Renci.SshNet.Tests.dll /TestCaseFilter:"TestCategory!=integration&TestCategory!=LongRunning"
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public void IsConnectedOnSessionShouldBeInvokedOnce()
}

[TestMethod]
public void SendMessageOnSessionShouldBeInvokedThreeTimes()
public void SendMessageOnSessionShouldBeInvokedOneTime()
{
// allow keep-alive to be sent once
Thread.Sleep(100);
Expand Down
4 changes: 4 additions & 0 deletions src/Renci.SshNet.Tests/Classes/Common/PacketDumpTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ public void Create_ByteArrayAndIndentLevel_IndentLevelLessThanZero()
catch (ArgumentOutOfRangeException ex)
{
Assert.IsNull(ex.InnerException);
#if NETFRAMEWORK
Assert.AreEqual(string.Format("Cannot be less than zero.{0}Parameter name: {1}", Environment.NewLine, ex.ParamName), ex.Message);
#else
Assert.AreEqual(string.Format("Cannot be less than zero. (Parameter '{1}')", Environment.NewLine, ex.ParamName), ex.Message);
#endif
Assert.AreEqual("indentLevel", ex.ParamName);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ protected override void SetupMocks()
.Setup(p => p.SendExecRequest(string.Format("scp -prf {0}", _transformedPath)))
.Returns(false);
_channelSessionMock.InSequence(sequence).Setup(p => p.Dispose());
#if NET35
_pipeStreamMock.As<IDisposable>().InSequence(sequence).Setup(p => p.Dispose());

// On .NET Core, Dispose() in turn invokes Close() and since we're not mocking
// an interface, we need to expect this call as well
_pipeStreamMock.Setup(p => p.Close());
#else
_pipeStreamMock.InSequence(sequence).Setup(p => p.Close());
#endif
}

protected override void Arrange()
Expand Down Expand Up @@ -106,7 +106,11 @@ public void DisposeOnChannelShouldBeInvokedOnce()
[TestMethod]
public void DisposeOnPipeStreamShouldBeInvokedOnce()
{
#if NET35
_pipeStreamMock.As<IDisposable>().Verify(p => p.Dispose(), Times.Once);
#else
_pipeStreamMock.Verify(p => p.Close(), Times.Once);
#endif
}

[TestMethod]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ protected override void SetupMocks()
_channelSessionMock.InSequence(sequence)
.Setup(p => p.SendExecRequest(string.Format("scp -pf {0}", _transformedPath))).Returns(false);
_channelSessionMock.InSequence(sequence).Setup(p => p.Dispose());
#if NET35
_pipeStreamMock.As<IDisposable>().InSequence(sequence).Setup(p => p.Dispose());

// On .NET Core, Dispose() in turn invokes Close() and since we're not mocking
// an interface, we need to expect this call as well
_pipeStreamMock.Setup(p => p.Close());
#else
_pipeStreamMock.InSequence(sequence).Setup(p => p.Close());
#endif
}

protected override void Arrange()
Expand Down Expand Up @@ -105,7 +105,11 @@ public void DisposeOnChannelShouldBeInvokedOnce()
[TestMethod]
public void DisposeOnPipeStreamShouldBeInvokedOnce()
{
#if NET35
_pipeStreamMock.As<IDisposable>().Verify(p => p.Dispose(), Times.Once);
#else
_pipeStreamMock.Verify(p => p.Close(), Times.Once);
#endif
}

[TestMethod]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ protected override void SetupMocks()
.Setup(p => p.SendExecRequest(string.Format("scp -f {0}", _transformedPath)))
.Returns(false);
_channelSessionMock.InSequence(sequence).Setup(p => p.Dispose());
#if NET35
_pipeStreamMock.As<IDisposable>().InSequence(sequence).Setup(p => p.Dispose());

// On .NET Core, Dispose() in turn invokes Close() and since we're not mocking
// an interface, we need to expect this call as well
_pipeStreamMock.Setup(p => p.Close());
#else
_pipeStreamMock.InSequence(sequence).Setup(p => p.Close());
#endif
}

protected override void Arrange()
Expand Down Expand Up @@ -116,7 +116,11 @@ public void DisposeOnChannelShouldBeInvokedOnce()
[TestMethod]
public void DisposeOnPipeStreamShouldBeInvokedOnce()
{
#if NET35
_pipeStreamMock.As<IDisposable>().Verify(p => p.Dispose(), Times.Once);
#else
_pipeStreamMock.Verify(p => p.Close(), Times.Once);
#endif
}

[TestMethod]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ protected override void SetupMocks()
.Setup(p => p.SendExecRequest(string.Format("scp -r -p -d -t {0}", _transformedPath)))
.Returns(false);
_channelSessionMock.InSequence(sequence).Setup(p => p.Dispose());
#if NET35
_pipeStreamMock.As<IDisposable>().InSequence(sequence).Setup(p => p.Dispose());

// On .NET Core, Dispose() in turn invokes Close() and since we're not mocking
// an interface, we need to expect this call as well
_pipeStreamMock.Setup(p => p.Close());
#else
_pipeStreamMock.InSequence(sequence).Setup(p => p.Close());
#endif
}

protected override void Arrange()
Expand Down Expand Up @@ -105,7 +105,11 @@ public void DisposeOnChannelShouldBeInvokedOnce()
[TestMethod]
public void DisposeOnPipeStreamShouldBeInvokedOnce()
{
#if NET35
_pipeStreamMock.As<IDisposable>().Verify(p => p.Dispose(), Times.Once);
#else
_pipeStreamMock.Verify(p => p.Close(), Times.Once);
#endif
}

[TestMethod]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,12 @@ protected override void SetupMocks()
.Setup(p => p.SendExecRequest(string.Format("scp -t -d {0}", _transformedPath)))
.Returns(false);
_channelSessionMock.InSequence(sequence).Setup(p => p.Dispose());
#if NET35
_pipeStreamMock.As<IDisposable>().InSequence(sequence).Setup(p => p.Dispose());

// On .NET Core, Dispose() in turn invokes Close() and since we're not mocking
// an interface, we need to expect this call as well
_pipeStreamMock.Setup(p => p.Close());
}
#else
_pipeStreamMock.InSequence(sequence).Setup(p => p.Close());
#endif
}

protected override void Arrange()
{
Expand Down Expand Up @@ -122,7 +122,11 @@ public void DisposeOnChannelShouldBeInvokedOnce()
[TestMethod]
public void DisposeOnPipeStreamShouldBeInvokedOnce()
{
#if NET35
_pipeStreamMock.As<IDisposable>().Verify(p => p.Dispose(), Times.Once);
#else
_pipeStreamMock.Verify(p => p.Close(), Times.Once);
#endif
}

[TestMethod]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,11 @@ protected override void SetupMocks()
p => p.SendData(It.Is<byte[]>(b => b.SequenceEqual(new byte[] {0}))));
_pipeStreamMock.InSequence(sequence).Setup(p => p.ReadByte()).Returns(0);
_channelSessionMock.InSequence(sequence).Setup(p => p.Dispose());
#if NET35
_pipeStreamMock.As<IDisposable>().InSequence(sequence).Setup(p => p.Dispose());

// On .NET Core, Dispose() in turn invokes Close() and since we're not mocking
// an interface, we need to expect this call as well
_pipeStreamMock.Setup(p => p.Close());
#else
_pipeStreamMock.InSequence(sequence).Setup(p => p.Close());
#endif
}

protected override void Arrange()
Expand Down Expand Up @@ -134,7 +134,11 @@ public void DisposeOnChannelShouldBeInvokedOnce()
[TestMethod]
public void DisposeOnPipeStreamShouldBeInvokedOnce()
{
#if NET35
_pipeStreamMock.As<IDisposable>().Verify(p => p.Dispose(), Times.Once);
#else
_pipeStreamMock.Verify(p => p.Close(), Times.Once);
#endif
}

[TestMethod]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ protected override void SetupMocks()
.Setup(p => p.SendExecRequest(string.Format("scp -t -d {0}", _transformedPath)))
.Returns(false);
_channelSessionMock.InSequence(sequence).Setup(p => p.Dispose());
#if NET35
_pipeStreamMock.As<IDisposable>().InSequence(sequence).Setup(p => p.Dispose());

// On .NET Core, Dispose() in turn invokes Close() and since we're not mocking
// an interface, we need to expect this call as well
_pipeStreamMock.Setup(p => p.Close());
#else
_pipeStreamMock.InSequence(sequence).Setup(p => p.Close());
#endif
}

protected override void Arrange()
Expand Down Expand Up @@ -119,7 +119,11 @@ public void DisposeOnChannelShouldBeInvokedOnce()
[TestMethod]
public void DisposeOnPipeStreamShouldBeInvokedOnce()
{
#if NET35
_pipeStreamMock.As<IDisposable>().Verify(p => p.Dispose(), Times.Once);
#else
_pipeStreamMock.Verify(p => p.Close(), Times.Once);
#endif
}

[TestMethod]
Expand Down
69 changes: 69 additions & 0 deletions src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamAsyncTestBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#if FEATURE_TAP
using System;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Renci.SshNet.Sftp;

namespace Renci.SshNet.Tests.Classes.Sftp
{
public abstract class SftpFileStreamAsyncTestBase
{
internal Mock<ISftpSession> SftpSessionMock;
protected MockSequence MockSequence;

protected virtual Task ArrangeAsync()
{
SetupData();
CreateMocks();
SetupMocks();
return Task.CompletedTask;
}

protected virtual void SetupData()
{
MockSequence = new MockSequence();
}

protected abstract void SetupMocks();

private void CreateMocks()
{
SftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
}

[TestInitialize]
public async Task SetUpAsync()
{
await ArrangeAsync();
await ActAsync();
}

protected abstract Task ActAsync();

protected byte[] GenerateRandom(int length)
{
return GenerateRandom(length, new Random());
}

protected byte[] GenerateRandom(int length, Random random)
{
var buffer = new byte[length];
random.NextBytes(buffer);
return buffer;
}

protected byte[] GenerateRandom(uint length)
{
return GenerateRandom(length, new Random());
}

protected byte[] GenerateRandom(uint length, Random random)
{
var buffer = new byte[length];
random.NextBytes(buffer);
return buffer;
}
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#if FEATURE_TAP
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Renci.SshNet.Sftp;

namespace Renci.SshNet.Tests.Classes.Sftp
{
[TestClass]
public class SftpFileStreamTest_OpenAsync_FileAccessInvalid : SftpFileStreamAsyncTestBase
{
private Random _random;
private string _path;
private FileMode _fileMode;
private FileAccess _fileAccess;
private int _bufferSize;
private ArgumentOutOfRangeException _actualException;

protected override void SetupData()
{
base.SetupData();

_random = new Random();
_path = _random.Next().ToString();
_fileMode = FileMode.Open;
_fileAccess = 0;
_bufferSize = _random.Next(5, 1000);
}

protected override void SetupMocks()
{
}

protected override async Task ActAsync()
{
try
{
await SftpFileStream.OpenAsync(SftpSessionMock.Object, _path, _fileMode, _fileAccess, _bufferSize, default);
Assert.Fail();
}
catch (ArgumentOutOfRangeException ex)
{
_actualException = ex;
}
}

[TestMethod]
public void CtorShouldHaveThrownArgumentException()
{
Assert.IsNotNull(_actualException);
Assert.IsNull(_actualException.InnerException);
Assert.AreEqual("access", _actualException.ParamName);
}
}
}
#endif
Loading

0 comments on commit 4dfc126

Please sign in to comment.