mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-20 11:45:43 +08:00
fix: time out and cancel propagation in managed client (#1987)
* fix: time out and cancel propagation in managed client * Update release notes * Refactor code --------- Co-authored-by: christian <6939810+chkr1011@users.noreply.github.com>
This commit is contained in:
@@ -7,12 +7,14 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Extensions.ManagedClient;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Internal;
|
||||
using MQTTnet.Packets;
|
||||
using MQTTnet.Protocol;
|
||||
using MQTTnet.Server;
|
||||
using MQTTnet.Tests.Mockups;
|
||||
@@ -574,16 +576,152 @@ namespace MQTTnet.Tests.Clients.ManagedMqttClient
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Subscribe_Does_Not_Hang_On_Server_Stop()
|
||||
{
|
||||
var timeout = TimeSpan.FromSeconds(2);
|
||||
var testTimeout = timeout * 2;
|
||||
const string topic = "test_topic_2";
|
||||
using (var testEnvironment = CreateTestEnvironment())
|
||||
using (var managedClient = await CreateManagedClientAsync(testEnvironment, timeout: timeout))
|
||||
{
|
||||
testEnvironment.IgnoreClientLogErrors = true;
|
||||
bool reject = true;
|
||||
var receivedOnServer = new SemaphoreSlim(0, 1);
|
||||
var failedOnClient = new SemaphoreSlim(0, 1);
|
||||
testEnvironment.Server.InterceptingInboundPacketAsync += e =>
|
||||
{
|
||||
if (e.Packet is MqttSubscribePacket)
|
||||
{
|
||||
if (reject)
|
||||
{
|
||||
e.ProcessPacket = false;
|
||||
}
|
||||
receivedOnServer.Release();
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
managedClient.SynchronizingSubscriptionsFailedAsync += e =>
|
||||
{
|
||||
failedOnClient.Release();
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
|
||||
await managedClient.SubscribeAsync(topic);
|
||||
Assert.IsTrue(await receivedOnServer.WaitAsync(testTimeout));
|
||||
Assert.IsTrue(await failedOnClient.WaitAsync(testTimeout));
|
||||
|
||||
reject = false;
|
||||
await managedClient.SubscribeAsync(topic);
|
||||
Assert.IsTrue(await receivedOnServer.WaitAsync(testTimeout));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Unsubscribe_Does_Not_Hang_On_Server_Stop()
|
||||
{
|
||||
var timeout = TimeSpan.FromSeconds(2);
|
||||
var testTimeout = timeout * 2;
|
||||
const string topic = "test_topic_2";
|
||||
using (var testEnvironment = CreateTestEnvironment())
|
||||
using (var managedClient = await CreateManagedClientAsync(testEnvironment, timeout: timeout))
|
||||
{
|
||||
testEnvironment.IgnoreClientLogErrors = true;
|
||||
bool reject = true;
|
||||
var receivedOnServer = new SemaphoreSlim(0, 1);
|
||||
var failedOnClient = new SemaphoreSlim(0, 1);
|
||||
testEnvironment.Server.InterceptingInboundPacketAsync += e =>
|
||||
{
|
||||
if (e.Packet is MqttUnsubscribePacket)
|
||||
{
|
||||
if (reject)
|
||||
{
|
||||
e.ProcessPacket = false;
|
||||
}
|
||||
receivedOnServer.Release();
|
||||
}
|
||||
else if (e.Packet is MqttSubscribePacket)
|
||||
{
|
||||
receivedOnServer.Release();
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
managedClient.SynchronizingSubscriptionsFailedAsync += e =>
|
||||
{
|
||||
failedOnClient.Release();
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
|
||||
await managedClient.SubscribeAsync(topic);
|
||||
Assert.IsTrue(await receivedOnServer.WaitAsync(testTimeout));
|
||||
|
||||
await managedClient.UnsubscribeAsync(topic);
|
||||
Assert.IsTrue(await receivedOnServer.WaitAsync(testTimeout));
|
||||
Assert.IsTrue(await failedOnClient.WaitAsync(testTimeout));
|
||||
|
||||
reject = false;
|
||||
await managedClient.UnsubscribeAsync(topic);
|
||||
Assert.IsTrue(await receivedOnServer.WaitAsync(testTimeout));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Publish_Does_Not_Hang_On_Server_Error()
|
||||
{
|
||||
var timeout = TimeSpan.FromSeconds(2);
|
||||
var testTimeout = timeout * 2;
|
||||
|
||||
const string topic = "test_topic_42";
|
||||
|
||||
using (var testEnvironment = CreateTestEnvironment())
|
||||
using (var managedClient = await CreateManagedClientAsync(testEnvironment, timeout: timeout))
|
||||
{
|
||||
testEnvironment.IgnoreClientLogErrors = true;
|
||||
bool reject = true;
|
||||
var receivedOnServer = new TaskCompletionSource();
|
||||
managedClient.ApplicationMessageProcessedAsync += e => Task.FromResult(reject &= e.Exception is null);
|
||||
testEnvironment.Server.InterceptingInboundPacketAsync += e =>
|
||||
{
|
||||
if (e.Packet is MqttPublishPacket)
|
||||
{
|
||||
if (reject)
|
||||
{
|
||||
e.ProcessPacket = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
receivedOnServer.TrySetResult();
|
||||
}
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
|
||||
|
||||
await managedClient.EnqueueAsync(new MqttApplicationMessage { Topic = topic, Payload = new byte[] { 1 }, Retain = true, QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce });
|
||||
|
||||
var timeoutTask = Task.Delay(testTimeout);
|
||||
|
||||
var firstDone = await Task.WhenAny(receivedOnServer.Task, timeoutTask);
|
||||
Assert.AreEqual(receivedOnServer.Task, firstDone, "Client is hung on publish!");
|
||||
}
|
||||
}
|
||||
|
||||
async Task<MQTTnet.Extensions.ManagedClient.ManagedMqttClient> CreateManagedClientAsync(
|
||||
TestEnvironment testEnvironment,
|
||||
IMqttClient underlyingClient = null,
|
||||
TimeSpan? connectionCheckInterval = null,
|
||||
string host = "localhost")
|
||||
string host = "localhost",
|
||||
TimeSpan? timeout = null)
|
||||
{
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var clientOptions = new MqttClientOptionsBuilder().WithTcpServer(host, testEnvironment.ServerPort);
|
||||
|
||||
if (timeout != null)
|
||||
{
|
||||
clientOptions.WithTimeout(timeout.Value);
|
||||
}
|
||||
|
||||
var managedOptions = new ManagedMqttClientOptionsBuilder().WithClientOptions(clientOptions).Build();
|
||||
|
||||
// Use a short connection check interval so that subscription operations are performed quickly
|
||||
|
||||
Reference in New Issue
Block a user