fix ConnectAsync not respecting the connection timeout (#1502)

This commit is contained in:
mus65
2024-09-22 13:05:32 +02:00
committed by GitHub
parent 4c5d0c075e
commit 28e674228f
2 changed files with 84 additions and 1 deletions
+11 -1
View File
@@ -307,7 +307,17 @@ namespace Renci.SshNet
DisposeSession(session);
}
Session = await CreateAndConnectSessionAsync(cancellationToken).ConfigureAwait(false);
using var timeoutCancellationTokenSource = new CancellationTokenSource(ConnectionInfo.Timeout);
using var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCancellationTokenSource.Token);
try
{
Session = await CreateAndConnectSessionAsync(linkedCancellationTokenSource.Token).ConfigureAwait(false);
}
catch (OperationCanceledException ex) when (timeoutCancellationTokenSource.IsCancellationRequested)
{
throw new SshOperationTimeoutException("Connection has timed out.", ex);
}
}
try
@@ -0,0 +1,73 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
#if !NET8_0_OR_GREATER
using Renci.SshNet.Abstractions;
#endif
using Renci.SshNet.Common;
using Renci.SshNet.Connection;
namespace Renci.SshNet.Tests.Classes
{
[TestClass]
public class BaseClientTest_ConnectAsync_Timeout
{
private BaseClient _client;
[TestInitialize]
public void Init()
{
var sessionMock = new Mock<ISession>();
var serviceFactoryMock = new Mock<IServiceFactory>();
var socketFactoryMock = new Mock<ISocketFactory>();
sessionMock.Setup(p => p.ConnectAsync(It.IsAny<CancellationToken>()))
.Returns<CancellationToken>(c => Task.Delay(Timeout.Infinite, c));
serviceFactoryMock.Setup(p => p.CreateSocketFactory())
.Returns(socketFactoryMock.Object);
var connectionInfo = new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "pwd"))
{
Timeout = TimeSpan.FromSeconds(1)
};
serviceFactoryMock.Setup(p => p.CreateSession(connectionInfo, socketFactoryMock.Object))
.Returns(sessionMock.Object);
_client = new MyClient(connectionInfo, false, serviceFactoryMock.Object);
}
[TestMethod]
public async Task ConnectAsyncWithTimeoutThrowsSshTimeoutException()
{
await Assert.ThrowsExceptionAsync<SshOperationTimeoutException>(() => _client.ConnectAsync(CancellationToken.None));
}
[TestMethod]
public async Task ConnectAsyncWithCancelledTokenThrowsOperationCancelledException()
{
using var cancellationTokenSource = new CancellationTokenSource();
await cancellationTokenSource.CancelAsync();
await Assert.ThrowsExceptionAsync<OperationCanceledException>(() => _client.ConnectAsync(cancellationTokenSource.Token));
}
[TestCleanup]
public void Cleanup()
{
_client?.Dispose();
}
private class MyClient : BaseClient
{
public MyClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, IServiceFactory serviceFactory) : base(connectionInfo, ownsConnectionInfo, serviceFactory)
{
}
}
}
}