Squashed commit of the following: 487-any-way-to-generate-events-on-receipt-of-puback-or-pubrec-packets

commit 3f2f8d4b0a31b20734eca3fff86c43bd1ac3e3ad
Merge: 34babbf2 d71ff3d6
Author: Christian <6939810+chkr1011@users.noreply.github.com>
Date:   Sat Jul 23 11:06:22 2022 +0200

    Merge branch 'master' into 487-any-way-to-generate-events-on-receipt-of-puback-or-pubrec-packets

commit 34babbf2714b742bc4f3802804a1a07159d38e22
Author: Christian <6939810+chkr1011@users.noreply.github.com>
Date:   Mon Jul 11 22:56:01 2022 +0200

    Fix typo.

commit add6277458f528fc03bf4a1ba228a55c5a8d1a80
Author: Christian <6939810+chkr1011@users.noreply.github.com>
Date:   Sat Jul 2 12:50:13 2022 +0200

    Add new event for client acknowledges.
This commit is contained in:
Christian
2022-07-23 11:08:53 +02:00
parent d71ff3d615
commit 0d7b020994
12 changed files with 625 additions and 379 deletions
+2 -144
View File
@@ -798,38 +798,7 @@ namespace MQTTnet.Tests.Server
Assert.IsTrue(longBody.SequenceEqual(receivedBody ?? new byte[0]));
}
}
[TestMethod]
public async Task Session_Takeover()
{
using (var testEnvironment = CreateTestEnvironment())
{
await testEnvironment.StartServer();
var options = new MqttClientOptionsBuilder().WithCleanSession(false)
.WithProtocolVersion(MqttProtocolVersion.V500) // Disconnect reason is only available in MQTT 5+
.WithClientId("a");
var client1 = await testEnvironment.ConnectClient(options);
await Task.Delay(500);
var disconnectReason = MqttClientDisconnectReason.NormalDisconnection;
client1.DisconnectedAsync += c =>
{
disconnectReason = c.Reason;
return PlatformAbstractionLayer.CompletedTask;
};
var client2 = await testEnvironment.ConnectClient(options);
await Task.Delay(500);
Assert.IsFalse(client1.IsConnected);
Assert.IsTrue(client2.IsConnected);
Assert.AreEqual(MqttClientDisconnectReason.SessionTakenOver, disconnectReason);
}
}
[TestMethod]
public async Task Set_Subscription_At_Server()
{
@@ -944,26 +913,6 @@ namespace MQTTnet.Tests.Server
}
}
[TestMethod]
public async Task Use_Clean_Session()
{
using (var testEnvironment = CreateTestEnvironment())
{
await testEnvironment.StartServer();
var client = testEnvironment.CreateClient();
var connectResult = await client.ConnectAsync(new MqttClientOptionsBuilder().WithTcpServer("localhost", testEnvironment.ServerPort).WithCleanSession().Build());
// Create the session including the subscription.
var client1 = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithClientId("a").WithCleanSession(false));
await client1.SubscribeAsync("x");
await client1.DisconnectAsync();
await Task.Delay(500);
Assert.IsFalse(connectResult.IsSessionPresent);
}
}
[TestMethod]
public async Task Use_Empty_Client_ID()
{
@@ -986,98 +935,7 @@ namespace MQTTnet.Tests.Server
Assert.IsTrue(client.IsConnected);
}
}
[TestMethod]
public async Task Will_Message_Do_Not_Send_On_Clean_Disconnect()
{
using (var testEnvironment = CreateTestEnvironment())
{
var receivedMessagesCount = 0;
await testEnvironment.StartServer();
var clientOptions = new MqttClientOptionsBuilder().WithWillTopic("My/last/will");
var c1 = await testEnvironment.ConnectClient();
c1.ApplicationMessageReceivedAsync += e =>
{
Interlocked.Increment(ref receivedMessagesCount);
return PlatformAbstractionLayer.CompletedTask;
};
await c1.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic("#").Build());
var c2 = await testEnvironment.ConnectClient(clientOptions);
await c2.DisconnectAsync().ConfigureAwait(false);
await Task.Delay(1000);
Assert.AreEqual(0, receivedMessagesCount);
}
}
[TestMethod]
public async Task Will_Message_Do_Not_Send_On_Takeover()
{
using (var testEnvironment = CreateTestEnvironment())
{
var receivedMessagesCount = 0;
await testEnvironment.StartServer();
// C1 will receive the last will!
var c1 = await testEnvironment.ConnectClient();
c1.ApplicationMessageReceivedAsync += e =>
{
Interlocked.Increment(ref receivedMessagesCount);
return PlatformAbstractionLayer.CompletedTask;
};
await c1.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic("#").Build());
// C2 has the last will defined.
var clientOptions = new MqttClientOptionsBuilder().WithWillTopic("My/last/will").WithClientId("WillOwner");
var c2 = await testEnvironment.ConnectClient(clientOptions);
// C3 will do the connection takeover.
var c3 = await testEnvironment.ConnectClient(clientOptions);
await Task.Delay(1000);
Assert.AreEqual(0, receivedMessagesCount);
}
}
[TestMethod]
public async Task Will_Message_Send()
{
using (var testEnvironment = CreateTestEnvironment())
{
await testEnvironment.StartServer();
var c1 = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder());
var receivedMessagesCount = 0;
c1.ApplicationMessageReceivedAsync += e =>
{
Interlocked.Increment(ref receivedMessagesCount);
return PlatformAbstractionLayer.CompletedTask;
};
await c1.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic("#").Build());
var clientOptions = new MqttClientOptionsBuilder().WithWillTopic("My/last/will").WithWillQualityOfServiceLevel(MqttQualityOfServiceLevel.AtMostOnce);
var c2 = await testEnvironment.ConnectClient(clientOptions);
c2.Dispose(); // Dispose will not send a DISCONNECT pattern first so the will message must be sent.
await Task.Delay(1000);
Assert.AreEqual(1, receivedMessagesCount);
}
}
void ConnectionValidationHandler(ValidatingConnectionEventArgs eventArgs)
{
if (_connected.ContainsKey(eventArgs.ClientId))
+124
View File
@@ -0,0 +1,124 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Client;
using MQTTnet.Implementations;
using MQTTnet.Protocol;
using MQTTnet.Server;
namespace MQTTnet.Tests.Server
{
[TestClass]
public sealed class QoS_Tests : BaseTestClass
{
[TestMethod]
public async Task Fire_Event_On_Client_Acknowledges_QoS_0()
{
using (var testEnvironment = CreateTestEnvironment())
{
var server = await testEnvironment.StartServer();
ClientAcknowledgedPublishPacketEventArgs eventArgs = null;
server.ClientAcknowledgedPublishPacketAsync += args =>
{
eventArgs = args;
return PlatformAbstractionLayer.CompletedTask;
};
var client1 = await testEnvironment.ConnectClient();
await client1.SubscribeAsync("A");
var client2 = await testEnvironment.ConnectClient();
await client2.PublishStringAsync("A");
await LongTestDelay();
// Must be null because no event should be fired for QoS 0.
Assert.IsNull(eventArgs);
}
}
[TestMethod]
public async Task Fire_Event_On_Client_Acknowledges_QoS_1()
{
using (var testEnvironment = CreateTestEnvironment())
{
var server = await testEnvironment.StartServer();
ClientAcknowledgedPublishPacketEventArgs eventArgs = null;
server.ClientAcknowledgedPublishPacketAsync += args =>
{
eventArgs = args;
return PlatformAbstractionLayer.CompletedTask;
};
var client1 = await testEnvironment.ConnectClient();
await client1.SubscribeAsync("A", MqttQualityOfServiceLevel.AtLeastOnce);
var client2 = await testEnvironment.ConnectClient();
await client2.PublishStringAsync("A", qualityOfServiceLevel: MqttQualityOfServiceLevel.AtLeastOnce);
await LongTestDelay();
Assert.IsNotNull(eventArgs);
Assert.IsNotNull(eventArgs.PublishPacket);
Assert.IsNotNull(eventArgs.AcknowledgePacket);
Assert.IsTrue(eventArgs.IsCompleted);
Assert.AreEqual("A", eventArgs.PublishPacket.Topic);
}
}
[TestMethod]
public async Task Fire_Event_On_Client_Acknowledges_QoS_2()
{
using (var testEnvironment = CreateTestEnvironment())
{
var server = await testEnvironment.StartServer();
var eventArgs = new List<ClientAcknowledgedPublishPacketEventArgs>();
server.ClientAcknowledgedPublishPacketAsync += args =>
{
lock (eventArgs)
{
eventArgs.Add(args);
}
return PlatformAbstractionLayer.CompletedTask;
};
var client1 = await testEnvironment.ConnectClient();
await client1.SubscribeAsync("A", MqttQualityOfServiceLevel.ExactlyOnce);
var client2 = await testEnvironment.ConnectClient();
await client2.PublishStringAsync("A", qualityOfServiceLevel: MqttQualityOfServiceLevel.ExactlyOnce);
await LongTestDelay();
Assert.AreEqual(2, eventArgs.Count);
var firstEvent = eventArgs[0];
Assert.IsNotNull(firstEvent);
Assert.IsNotNull(firstEvent.PublishPacket);
Assert.IsNotNull(firstEvent.AcknowledgePacket);
Assert.IsFalse(firstEvent.IsCompleted);
Assert.AreEqual("A", firstEvent.PublishPacket.Topic);
var secondEvent = eventArgs[1];
Assert.IsNotNull(secondEvent);
Assert.IsNotNull(secondEvent.PublishPacket);
Assert.IsNotNull(secondEvent.AcknowledgePacket);
Assert.IsTrue(secondEvent.IsCompleted);
Assert.AreEqual("A", secondEvent.PublishPacket.Topic);
}
}
}
}
@@ -2,10 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Adapter;
using MQTTnet.Client;
+84 -1
View File
@@ -14,7 +14,6 @@ using MQTTnet.Implementations;
using MQTTnet.Protocol;
using MQTTnet.Server;
using MQTTnet.Tests.Mockups;
using MqttClient = MQTTnet.Client.MqttClient;
namespace MQTTnet.Tests.Server
{
@@ -220,6 +219,37 @@ namespace MQTTnet.Tests.Server
}
}
[TestMethod]
public async Task Session_Takeover()
{
using (var testEnvironment = CreateTestEnvironment())
{
await testEnvironment.StartServer();
var options = new MqttClientOptionsBuilder().WithCleanSession(false)
.WithProtocolVersion(MqttProtocolVersion.V500) // Disconnect reason is only available in MQTT 5+
.WithClientId("a");
var client1 = await testEnvironment.ConnectClient(options);
await Task.Delay(500);
var disconnectReason = MqttClientDisconnectReason.NormalDisconnection;
client1.DisconnectedAsync += c =>
{
disconnectReason = c.Reason;
return PlatformAbstractionLayer.CompletedTask;
};
var client2 = await testEnvironment.ConnectClient(options);
await Task.Delay(500);
Assert.IsFalse(client1.IsConnected);
Assert.IsTrue(client2.IsConnected);
Assert.AreEqual(MqttClientDisconnectReason.SessionTakenOver, disconnectReason);
}
}
[TestMethod]
public async Task Set_Session_Item()
{
@@ -277,6 +307,59 @@ namespace MQTTnet.Tests.Server
}
}
[TestMethod]
public async Task Use_Clean_Session()
{
using (var testEnvironment = CreateTestEnvironment())
{
await testEnvironment.StartServer();
var client = testEnvironment.CreateClient();
var connectResult = await client.ConnectAsync(new MqttClientOptionsBuilder().WithTcpServer("localhost", testEnvironment.ServerPort).WithCleanSession().Build());
// Create the session including the subscription.
var client1 = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithClientId("a").WithCleanSession(false));
await client1.SubscribeAsync("x");
await client1.DisconnectAsync();
await Task.Delay(500);
Assert.IsFalse(connectResult.IsSessionPresent);
}
}
[TestMethod]
public async Task Will_Message_Do_Not_Send_On_Takeover()
{
using (var testEnvironment = CreateTestEnvironment())
{
var receivedMessagesCount = 0;
await testEnvironment.StartServer();
// C1 will receive the last will!
var c1 = await testEnvironment.ConnectClient();
c1.ApplicationMessageReceivedAsync += e =>
{
Interlocked.Increment(ref receivedMessagesCount);
return PlatformAbstractionLayer.CompletedTask;
};
await c1.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic("#").Build());
// C2 has the last will defined.
var clientOptions = new MqttClientOptionsBuilder().WithWillTopic("My/last/will").WithClientId("WillOwner");
var c2 = await testEnvironment.ConnectClient(clientOptions);
// C3 will do the connection takeover.
var c3 = await testEnvironment.ConnectClient(clientOptions);
await Task.Delay(1000);
Assert.AreEqual(0, receivedMessagesCount);
}
}
async Task<IMqttClient> ConnectAndSubscribe(TestEnvironment testEnvironment, MqttClientOptionsBuilder options, Action onReceive)
{
try
+71
View File
@@ -0,0 +1,71 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Client;
using MQTTnet.Implementations;
using MQTTnet.Protocol;
namespace MQTTnet.Tests.Server
{
[TestClass]
public sealed class Will_Tests : BaseTestClass
{
[TestMethod]
public async Task Will_Message_Do_Not_Send_On_Clean_Disconnect()
{
using (var testEnvironment = CreateTestEnvironment())
{
var receivedMessagesCount = 0;
await testEnvironment.StartServer();
var clientOptions = new MqttClientOptionsBuilder().WithWillTopic("My/last/will");
var c1 = await testEnvironment.ConnectClient();
c1.ApplicationMessageReceivedAsync += e =>
{
Interlocked.Increment(ref receivedMessagesCount);
return PlatformAbstractionLayer.CompletedTask;
};
await c1.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic("#").Build());
var c2 = await testEnvironment.ConnectClient(clientOptions);
await c2.DisconnectAsync().ConfigureAwait(false);
await Task.Delay(1000);
Assert.AreEqual(0, receivedMessagesCount);
}
}
[TestMethod]
public async Task Will_Message_Send()
{
using (var testEnvironment = CreateTestEnvironment())
{
await testEnvironment.StartServer();
var c1 = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder());
var receivedMessagesCount = 0;
c1.ApplicationMessageReceivedAsync += e =>
{
Interlocked.Increment(ref receivedMessagesCount);
return PlatformAbstractionLayer.CompletedTask;
};
await c1.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic("#").Build());
var clientOptions = new MqttClientOptionsBuilder().WithWillTopic("My/last/will").WithWillQualityOfServiceLevel(MqttQualityOfServiceLevel.AtMostOnce);
var c2 = await testEnvironment.ConnectClient(clientOptions);
c2.Dispose(); // Dispose will not send a DISCONNECT pattern first so the will message must be sent.
await Task.Delay(1000);
Assert.AreEqual(1, receivedMessagesCount);
}
}
}
}