Improve topic comparer.

This commit is contained in:
Christian
2021-10-02 20:44:12 +02:00
parent 0920c86d37
commit db00682c75
13 changed files with 598 additions and 398 deletions
@@ -37,13 +37,13 @@ namespace MQTTnet.Benchmarks
{
for (var i = 0; i < 10000; i++)
{
MqttTopicFilterComparer.IsMatch("sport/tennis/player1", "sport/#");
MqttTopicFilterComparer.IsMatch("sport/tennis/player1/ranking", "sport/#/ranking");
MqttTopicFilterComparer.IsMatch("sport/tennis/player1/score/wimbledon", "sport/+/player1/#");
MqttTopicFilterComparer.IsMatch("sport/tennis/player1", "sport/tennis/+");
MqttTopicFilterComparer.IsMatch("/finance", "+/+");
MqttTopicFilterComparer.IsMatch("/finance", "/+");
MqttTopicFilterComparer.IsMatch("/finance", "+");
MqttTopicFilterComparer.Compare("sport/tennis/player1", "sport/#");
MqttTopicFilterComparer.Compare("sport/tennis/player1/ranking", "sport/#/ranking");
MqttTopicFilterComparer.Compare("sport/tennis/player1/score/wimbledon", "sport/+/player1/#");
MqttTopicFilterComparer.Compare("sport/tennis/player1", "sport/tennis/+");
MqttTopicFilterComparer.Compare("/finance", "+/+");
MqttTopicFilterComparer.Compare("/finance", "/+");
MqttTopicFilterComparer.Compare("/finance", "+");
}
}
+1 -242
View File
@@ -202,248 +202,7 @@ namespace MQTTnet.Tests.Server
Assert.AreEqual(1, receivedMessagesCount);
}
}
[TestMethod]
public async Task Intercept_Subscription()
{
using (var testEnvironment = new TestEnvironment(TestContext))
{
await testEnvironment.StartServer(new MqttServerOptionsBuilder().WithSubscriptionInterceptor(
c =>
{
// Set the topic to "a" regards what the client wants to subscribe.
c.TopicFilter.Topic = "a";
}));
var topicAReceived = false;
var topicBReceived = false;
var client = await testEnvironment.ConnectClient();
client.UseApplicationMessageReceivedHandler(c =>
{
if (c.ApplicationMessage.Topic == "a")
{
topicAReceived = true;
}
else if (c.ApplicationMessage.Topic == "b")
{
topicBReceived = true;
}
});
await client.SubscribeAsync("b");
await client.PublishAsync("a");
await Task.Delay(500);
Assert.IsTrue(topicAReceived);
Assert.IsFalse(topicBReceived);
}
}
[TestMethod]
public async Task Subscribe_Unsubscribe()
{
using (var testEnvironment = new TestEnvironment(TestContext))
{
var receivedMessagesCount = 0;
var server = await testEnvironment.StartServer();
var c1 = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithClientId("c1"));
c1.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
var c2 = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithClientId("c2"));
var message = new MqttApplicationMessageBuilder().WithTopic("a").WithAtLeastOnceQoS().Build();
await c2.PublishAsync(message);
await Task.Delay(500);
Assert.AreEqual(0, receivedMessagesCount);
var subscribeEventCalled = false;
server.ClientSubscribedTopicHandler = new MqttServerClientSubscribedTopicHandlerDelegate(e =>
{
subscribeEventCalled = e.TopicFilter.Topic == "a" && e.ClientId == c1.Options.ClientId;
});
await c1.SubscribeAsync(new MqttTopicFilter { Topic = "a", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce });
await Task.Delay(250);
Assert.IsTrue(subscribeEventCalled, "Subscribe event not called.");
await c2.PublishAsync(message);
await Task.Delay(250);
Assert.AreEqual(1, receivedMessagesCount);
var unsubscribeEventCalled = false;
server.ClientUnsubscribedTopicHandler = new MqttServerClientUnsubscribedTopicHandlerDelegate(e =>
{
unsubscribeEventCalled = e.TopicFilter == "a" && e.ClientId == c1.Options.ClientId;
});
await c1.UnsubscribeAsync("a");
await Task.Delay(250);
Assert.IsTrue(unsubscribeEventCalled, "Unsubscribe event not called.");
await c2.PublishAsync(message);
await Task.Delay(500);
Assert.AreEqual(1, receivedMessagesCount);
await Task.Delay(500);
Assert.AreEqual(1, receivedMessagesCount);
}
}
[TestMethod]
public async Task Subscribe_Multiple_In_Single_Request()
{
using (var testEnvironment = new TestEnvironment(TestContext))
{
var receivedMessagesCount = 0;
await testEnvironment.StartServer();
var c1 = await testEnvironment.ConnectClient();
c1.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
await c1.SubscribeAsync(new MqttClientSubscribeOptionsBuilder()
.WithTopicFilter("a")
.WithTopicFilter("b")
.WithTopicFilter("c")
.Build());
var c2 = await testEnvironment.ConnectClient();
await c2.PublishAsync("a");
await Task.Delay(100);
Assert.AreEqual(receivedMessagesCount, 1);
await c2.PublishAsync("b");
await Task.Delay(100);
Assert.AreEqual(receivedMessagesCount, 2);
await c2.PublishAsync("c");
await Task.Delay(100);
Assert.AreEqual(receivedMessagesCount, 3);
}
}
[TestMethod]
public async Task Subscribe_Lots_In_Single_Request()
{
using (var testEnvironment = new TestEnvironment(TestContext))
{
var receivedMessagesCount = 0;
await testEnvironment.StartServer();
var c1 = await testEnvironment.ConnectClient();
c1.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
var optionsBuilder = new MqttClientSubscribeOptionsBuilder();
for (var i = 0; i < 500; i++)
{
optionsBuilder.WithTopicFilter(i.ToString(), MqttQualityOfServiceLevel.AtMostOnce);
}
await c1.SubscribeAsync(optionsBuilder.Build()).ConfigureAwait(false);
var c2 = await testEnvironment.ConnectClient();
var messageBuilder = new MqttApplicationMessageBuilder();
for (var i = 0; i < 500; i++)
{
messageBuilder.WithTopic(i.ToString());
await c2.PublishAsync(messageBuilder.Build()).ConfigureAwait(false);
}
SpinWait.SpinUntil(() => receivedMessagesCount == 500, TimeSpan.FromSeconds(20));
Assert.AreEqual(500, receivedMessagesCount);
}
}
[TestMethod]
public async Task Subscribe_Lots_In_Multiple_Requests()
{
using (var testEnvironment = new TestEnvironment(TestContext))
{
var receivedMessagesCount = 0;
await testEnvironment.StartServer();
var c1 = await testEnvironment.ConnectClient();
c1.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
for (var i = 0; i < 500; i++)
{
var so = new MqttClientSubscribeOptionsBuilder()
.WithTopicFilter(i.ToString()).Build();
await c1.SubscribeAsync(so).ConfigureAwait(false);
await Task.Delay(10);
}
var c2 = await testEnvironment.ConnectClient();
var messageBuilder = new MqttApplicationMessageBuilder();
for (var i = 0; i < 500; i++)
{
messageBuilder.WithTopic(i.ToString());
await c2.PublishAsync(messageBuilder.Build()).ConfigureAwait(false);
await Task.Delay(10);
}
SpinWait.SpinUntil(() => receivedMessagesCount == 500, 5000);
Assert.AreEqual(500, receivedMessagesCount);
}
}
[TestMethod]
public async Task Subscribe_Multiple_In_Multiple_Request()
{
using (var testEnvironment = new TestEnvironment(TestContext))
{
var receivedMessagesCount = 0;
await testEnvironment.StartServer();
var c1 = await testEnvironment.ConnectClient();
c1.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
await c1.SubscribeAsync(new MqttClientSubscribeOptionsBuilder()
.WithTopicFilter("a")
.Build());
await c1.SubscribeAsync(new MqttClientSubscribeOptionsBuilder()
.WithTopicFilter("b")
.Build());
await c1.SubscribeAsync(new MqttClientSubscribeOptionsBuilder()
.WithTopicFilter("c")
.Build());
var c2 = await testEnvironment.ConnectClient();
await c2.PublishAsync("a");
await Task.Delay(100);
Assert.AreEqual(receivedMessagesCount, 1);
await c2.PublishAsync("b");
await Task.Delay(100);
Assert.AreEqual(receivedMessagesCount, 2);
await c2.PublishAsync("c");
await Task.Delay(100);
Assert.AreEqual(receivedMessagesCount, 3);
}
}
[TestMethod]
public async Task Publish_From_Server()
{
@@ -1,6 +1,7 @@
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Client;
using MQTTnet.Client.Subscribing;
using MQTTnet.Formatter;
namespace MQTTnet.Tests.Server
@@ -23,5 +24,23 @@ namespace MQTTnet.Tests.Server
Assert.IsFalse(connectResult.SharedSubscriptionAvailable);
}
}
[TestMethod]
public async Task Subscription_Of_Shared_Subscription_Is_Denied()
{
using (var testEnvironment = CreateTestEnvironment(MqttProtocolVersion.V500))
{
await testEnvironment.StartServer();
var client = testEnvironment.CreateClient();
await client.ConnectAsync(testEnvironment.Factory.CreateClientOptionsBuilder()
.WithProtocolVersion(MqttProtocolVersion.V500)
.WithTcpServer("127.0.0.1", testEnvironment.ServerPort).Build());
var subscribeResult = await client.SubscribeAsync("$share/A");
Assert.AreEqual(MqttClientSubscribeResultCode.SharedSubscriptionsNotSupported, subscribeResult.Items[0].ResultCode);
}
}
}
}
@@ -0,0 +1,282 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Client;
using MQTTnet.Client.Options;
using MQTTnet.Client.Subscribing;
using MQTTnet.Formatter;
using MQTTnet.Protocol;
using MQTTnet.Server;
namespace MQTTnet.Tests.Server
{
[TestClass]
public sealed class Subscribe_Tests : BaseTestClass
{
[TestMethod]
public async Task Intercept_Subscription()
{
using (var testEnvironment = CreateTestEnvironment())
{
await testEnvironment.StartServer(new MqttServerOptionsBuilder().WithSubscriptionInterceptor(
c =>
{
// Set the topic to "a" regards what the client wants to subscribe.
c.TopicFilter.Topic = "a";
}));
var topicAReceived = false;
var topicBReceived = false;
var client = await testEnvironment.ConnectClient();
client.UseApplicationMessageReceivedHandler(c =>
{
if (c.ApplicationMessage.Topic == "a")
{
topicAReceived = true;
}
else if (c.ApplicationMessage.Topic == "b")
{
topicBReceived = true;
}
});
await client.SubscribeAsync("b");
await client.PublishAsync("a");
await Task.Delay(500);
Assert.IsTrue(topicAReceived);
Assert.IsFalse(topicBReceived);
}
}
[TestMethod]
public async Task Subscribe_Unsubscribe()
{
using (var testEnvironment = CreateTestEnvironment())
{
var receivedMessagesCount = 0;
var server = await testEnvironment.StartServer();
var c1 = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithClientId("c1"));
c1.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
var c2 = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithClientId("c2"));
var message = new MqttApplicationMessageBuilder().WithTopic("a").WithAtLeastOnceQoS().Build();
await c2.PublishAsync(message);
await Task.Delay(500);
Assert.AreEqual(0, receivedMessagesCount);
var subscribeEventCalled = false;
server.ClientSubscribedTopicHandler = new MqttServerClientSubscribedTopicHandlerDelegate(e =>
{
subscribeEventCalled = e.TopicFilter.Topic == "a" && e.ClientId == c1.Options.ClientId;
});
await c1.SubscribeAsync(new MqttTopicFilter { Topic = "a", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce });
await Task.Delay(250);
Assert.IsTrue(subscribeEventCalled, "Subscribe event not called.");
await c2.PublishAsync(message);
await Task.Delay(250);
Assert.AreEqual(1, receivedMessagesCount);
var unsubscribeEventCalled = false;
server.ClientUnsubscribedTopicHandler = new MqttServerClientUnsubscribedTopicHandlerDelegate(e =>
{
unsubscribeEventCalled = e.TopicFilter == "a" && e.ClientId == c1.Options.ClientId;
});
await c1.UnsubscribeAsync("a");
await Task.Delay(250);
Assert.IsTrue(unsubscribeEventCalled, "Unsubscribe event not called.");
await c2.PublishAsync(message);
await Task.Delay(500);
Assert.AreEqual(1, receivedMessagesCount);
await Task.Delay(500);
Assert.AreEqual(1, receivedMessagesCount);
}
}
[TestMethod]
public async Task Subscribe_Multiple_In_Single_Request()
{
using (var testEnvironment = CreateTestEnvironment())
{
var receivedMessagesCount = 0;
await testEnvironment.StartServer();
var c1 = await testEnvironment.ConnectClient();
c1.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
await c1.SubscribeAsync(new MqttClientSubscribeOptionsBuilder()
.WithTopicFilter("a")
.WithTopicFilter("b")
.WithTopicFilter("c")
.Build());
var c2 = await testEnvironment.ConnectClient();
await c2.PublishAsync("a");
await Task.Delay(100);
Assert.AreEqual(receivedMessagesCount, 1);
await c2.PublishAsync("b");
await Task.Delay(100);
Assert.AreEqual(receivedMessagesCount, 2);
await c2.PublishAsync("c");
await Task.Delay(100);
Assert.AreEqual(receivedMessagesCount, 3);
}
}
[TestMethod]
public async Task Subscribe_Lots_In_Single_Request()
{
using (var testEnvironment = CreateTestEnvironment())
{
var receivedMessagesCount = 0;
await testEnvironment.StartServer();
var c1 = await testEnvironment.ConnectClient();
c1.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
var optionsBuilder = new MqttClientSubscribeOptionsBuilder();
for (var i = 0; i < 500; i++)
{
optionsBuilder.WithTopicFilter(i.ToString());
}
await c1.SubscribeAsync(optionsBuilder.Build()).ConfigureAwait(false);
var c2 = await testEnvironment.ConnectClient();
var messageBuilder = new MqttApplicationMessageBuilder();
for (var i = 0; i < 500; i++)
{
messageBuilder.WithTopic(i.ToString());
await c2.PublishAsync(messageBuilder.Build()).ConfigureAwait(false);
}
SpinWait.SpinUntil(() => receivedMessagesCount == 500, TimeSpan.FromSeconds(20));
Assert.AreEqual(500, receivedMessagesCount);
}
}
[TestMethod]
public async Task Subscribe_Lots_In_Multiple_Requests()
{
using (var testEnvironment = CreateTestEnvironment())
{
var receivedMessagesCount = 0;
await testEnvironment.StartServer();
var c1 = await testEnvironment.ConnectClient();
c1.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
for (var i = 0; i < 500; i++)
{
var so = new MqttClientSubscribeOptionsBuilder()
.WithTopicFilter(i.ToString()).Build();
await c1.SubscribeAsync(so).ConfigureAwait(false);
await Task.Delay(10);
}
var c2 = await testEnvironment.ConnectClient();
var messageBuilder = new MqttApplicationMessageBuilder();
for (var i = 0; i < 500; i++)
{
messageBuilder.WithTopic(i.ToString());
await c2.PublishAsync(messageBuilder.Build()).ConfigureAwait(false);
await Task.Delay(10);
}
SpinWait.SpinUntil(() => receivedMessagesCount == 500, 5000);
Assert.AreEqual(500, receivedMessagesCount);
}
}
[TestMethod]
public async Task Subscribe_Multiple_In_Multiple_Request()
{
using (var testEnvironment = CreateTestEnvironment())
{
var receivedMessagesCount = 0;
await testEnvironment.StartServer();
var c1 = await testEnvironment.ConnectClient();
c1.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
await c1.SubscribeAsync(new MqttClientSubscribeOptionsBuilder()
.WithTopicFilter("a")
.Build());
await c1.SubscribeAsync(new MqttClientSubscribeOptionsBuilder()
.WithTopicFilter("b")
.Build());
await c1.SubscribeAsync(new MqttClientSubscribeOptionsBuilder()
.WithTopicFilter("c")
.Build());
var c2 = await testEnvironment.ConnectClient();
await c2.PublishAsync("a");
await Task.Delay(100);
Assert.AreEqual(receivedMessagesCount, 1);
await c2.PublishAsync("b");
await Task.Delay(100);
Assert.AreEqual(receivedMessagesCount, 2);
await c2.PublishAsync("c");
await Task.Delay(100);
Assert.AreEqual(receivedMessagesCount, 3);
}
}
[TestMethod]
public async Task Deny_Invalid_Topic()
{
using (var testEnvironment = CreateTestEnvironment(MqttProtocolVersion.V500))
{
await testEnvironment.StartServer(new MqttServerOptionsBuilder().WithSubscriptionInterceptor(
c =>
{
if (c.TopicFilter.Topic == "not_allowed_topic")
{
c.ReasonCode = MqttSubscribeReasonCode.TopicFilterInvalid;
}
}));
var client = await testEnvironment.ConnectClient();
var subscribeResult =await client.SubscribeAsync("allowed_topic");
Assert.AreEqual(MqttClientSubscribeResultCode.GrantedQoS0, subscribeResult.Items[0].ResultCode);
subscribeResult =await client.SubscribeAsync("not_allowed_topic");
Assert.AreEqual(MqttClientSubscribeResultCode.TopicFilterInvalid, subscribeResult.Items[0].ResultCode);
}
}
}
}
@@ -4,111 +4,135 @@ using MQTTnet.Server.Internal;
namespace MQTTnet.Tests.Server
{
[TestClass]
public class TopicFilterComparer_Tests
public sealed class MqttTopicFilterComparer_Tests
{
[TestMethod]
public void TopicFilterComparer_Plus_Match_With_Separator_Only()
public void Plus_Match_With_Separator_Only()
{
//A Topic Name or Topic Filter consisting only of the ‘/’ character is valid
CompareAndAssert("A", "+", true);
CompareAndAssert("A", "+", MqttTopicFilterCompareResult.IsMatch);
}
[TestMethod]
public void TopicFilterComparer_Hash_Match_With_Separator_Only()
public void Hash_Match_With_Separator_Only()
{
//A Topic Name or Topic Filter consisting only of the ‘/’ character is valid
CompareAndAssert("/", "#", true);
CompareAndAssert("/", "#", MqttTopicFilterCompareResult.IsMatch);
}
[TestMethod]
public void TopicFilterComparer_DirectMatch()
public void DirectMatch()
{
CompareAndAssert("A/B/C", "A/B/C", true);
CompareAndAssert("A/B/C", "A/B/C", MqttTopicFilterCompareResult.IsMatch);
}
[TestMethod]
public void TopicFilterComparer_DirectNoMatch()
public void DirectNoMatch()
{
CompareAndAssert("A/B/X", "A/B/C", false);
CompareAndAssert("A/B/X", "A/B/C", MqttTopicFilterCompareResult.NoMatch);
}
[TestMethod]
public void TopicFilterComparer_MiddleOneLevelWildcardMatch()
public void MiddleOneLevelWildcardMatch()
{
CompareAndAssert("A/B/C", "A/+/C", true);
CompareAndAssert("A/B/C", "A/+/C", MqttTopicFilterCompareResult.IsMatch);
}
[TestMethod]
public void TopicFilterComparer_MiddleOneLevelWildcardNoMatch()
public void MiddleOneLevelWildcardNoMatch()
{
CompareAndAssert("A/B/C/D", "A/+/C", false);
CompareAndAssert("A/B/C/D", "A/+/C", MqttTopicFilterCompareResult.NoMatch);
}
[TestMethod]
public void TopicFilterComparer_BeginningOneLevelWildcardMatch()
public void BeginningOneLevelWildcardMatch()
{
CompareAndAssert("A/B/C", "+/B/C", true);
CompareAndAssert("A/B/C", "+/B/C", MqttTopicFilterCompareResult.IsMatch);
}
[TestMethod]
public void TopicFilterComparer_EndOneLevelWildcardMatch()
public void EndOneLevelWildcardMatch()
{
CompareAndAssert("A/B/C", "A/B/+", true);
CompareAndAssert("A/B/C", "A/B/+", MqttTopicFilterCompareResult.IsMatch);
}
[TestMethod]
public void TopicFilterComparer_EndMultipleLevelsWildcardMatch()
public void EndMultipleLevelsWildcardMatch()
{
CompareAndAssert("A/B/C", "A/#", true);
CompareAndAssert("A/B/C", "A/#", MqttTopicFilterCompareResult.IsMatch);
}
[TestMethod]
public void TopicFilterComparer_EndMultipleLevelsWildcardNoMatch()
public void EndMultipleLevelsWildcardNoMatch()
{
CompareAndAssert("A/B/C/D", "A/C/#", false);
CompareAndAssert("A/B/C/D", "A/C/#", MqttTopicFilterCompareResult.NoMatch);
}
[TestMethod]
public void TopicFilterComparer_EndMultipleLevelsWildcardMatchEmptyLevel()
public void EndMultipleLevelsWildcardMatchEmptyLevel()
{
CompareAndAssert("A/", "A/#", true);
CompareAndAssert("A/", "A/#", MqttTopicFilterCompareResult.IsMatch);
}
[TestMethod]
public void TopicFilterComparer_AllLevelsWildcardMatch()
public void AllLevelsWildcardMatch()
{
CompareAndAssert("A/B/C/D", "#", true);
CompareAndAssert("A/B/C/D", "#", MqttTopicFilterCompareResult.IsMatch);
}
[TestMethod]
public void TopicFilterComparer_MultiLevel_Sport()
public void MultiLevel_Sport()
{
// Tests from official MQTT spec (4.7.1.2 Multi-level wildcard)
CompareAndAssert("sport/tennis/player1", "sport/tennis/player1/#", true);
CompareAndAssert("sport/tennis/player1/ranking", "sport/tennis/player1/#", true);
CompareAndAssert("sport/tennis/player1/score/wimbledon", "sport/tennis/player1/#", true);
CompareAndAssert("sport/tennis/player1", "sport/tennis/player1/#", MqttTopicFilterCompareResult.IsMatch);
CompareAndAssert("sport/tennis/player1/ranking", "sport/tennis/player1/#", MqttTopicFilterCompareResult.IsMatch);
CompareAndAssert("sport/tennis/player1/score/wimbledon", "sport/tennis/player1/#", MqttTopicFilterCompareResult.IsMatch);
CompareAndAssert("sport/tennis/player1", "sport/tennis/+", true);
CompareAndAssert("sport/tennis/player2", "sport/tennis/+", true);
CompareAndAssert("sport/tennis/player1/ranking", "sport/tennis/+", false);
CompareAndAssert("sport/tennis/player1", "sport/tennis/+", MqttTopicFilterCompareResult.IsMatch);
CompareAndAssert("sport/tennis/player2", "sport/tennis/+", MqttTopicFilterCompareResult.IsMatch);
CompareAndAssert("sport/tennis/player1/ranking", "sport/tennis/+", MqttTopicFilterCompareResult.NoMatch);
CompareAndAssert("sport", "sport/#", true);
CompareAndAssert("sport", "sport/+", false);
CompareAndAssert("sport/", "sport/+", true);
CompareAndAssert("sport", "sport/#", MqttTopicFilterCompareResult.IsMatch);
CompareAndAssert("sport", "sport/+", MqttTopicFilterCompareResult.NoMatch);
CompareAndAssert("sport/", "sport/+", MqttTopicFilterCompareResult.IsMatch);
}
[TestMethod]
public void TopicFilterComparer_SingleLevel_Finance()
public void SingleLevel_Finance()
{
// Tests from official MQTT spec (4.7.1.3 Single level wildcard)
CompareAndAssert("/finance", "+/+", true);
CompareAndAssert("/finance", "/+", true);
CompareAndAssert("/finance", "+", false);
CompareAndAssert("/finance", "+/+", MqttTopicFilterCompareResult.IsMatch);
CompareAndAssert("/finance", "/+", MqttTopicFilterCompareResult.IsMatch);
CompareAndAssert("/finance", "+", MqttTopicFilterCompareResult.NoMatch);
}
private static void CompareAndAssert(string topic, string filter, bool expectedResult)
[TestMethod]
public void Reserved_Multi_Level_Wildcard_Only()
{
Assert.AreEqual(expectedResult, MqttTopicFilterComparer.IsMatch(topic, filter));
CompareAndAssert("$SPECIAL/TOPIC", "#", MqttTopicFilterCompareResult.NoMatch);
}
[TestMethod]
public void Reserved_Single_Level_Wildcard_Prefix()
{
CompareAndAssert("$SYS/monitor/Clients", "+/monitor/Clients", MqttTopicFilterCompareResult.NoMatch);
}
[TestMethod]
public void Reserved_Single_Level_Wildcard_Suffix()
{
CompareAndAssert("$SYS/monitor/Clients", "$SYS/monitor/+", MqttTopicFilterCompareResult.IsMatch);
}
[TestMethod]
public void Reserved_Single_Level_Wildcard()
{
CompareAndAssert("$SYS/monitor/Clients", "$SYS/#", MqttTopicFilterCompareResult.IsMatch);
}
static void CompareAndAssert(string topic, string filter, MqttTopicFilterCompareResult expectedResult)
{
Assert.AreEqual(expectedResult, MqttTopicFilterComparer.Compare(topic, filter));
}
}
}
+1 -1
View File
@@ -55,7 +55,7 @@ namespace MQTTnet.TestApp.NetCore
ApplicationMessageInterceptor = new MqttServerApplicationMessageInterceptorDelegate(context =>
{
if (MqttTopicFilterComparer.IsMatch(context.ApplicationMessage.Topic, "/myTopic/WithTimestamp/#"))
if (MqttTopicFilterComparer.Compare(context.ApplicationMessage.Topic, "/myTopic/WithTimestamp/#") == MqttTopicFilterCompareResult.IsMatch)
{
// Replace the payload with the timestamp. But also extending a JSON
// based payload with the timestamp is a suitable use case.