mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-25 07:41:32 +08:00
Allow user properties as pre-encoded UTF-8 binary buffer (#2228)
* Add support for binary user properties in MQTT 5.0 * Optimize byte array reversal in SubscriptionTopicHashTests * Use InvariantCulture for topic string conversion in Load_Tests * switched to `Microsoft.Testing.Platform` * Refactor CI workflow to separate signed and unsigned package builds * Add condition to sign job to prevent execution on external pull requests * Remove fallback to value as string in MqttUserProperty * Refactor MqttUserProperty handling to use byte arrays for improved performance and add deprecation warnings for legacy methods
This commit is contained in:
@@ -6,6 +6,7 @@ using System.Text;
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Internal;
|
||||
using MQTTnet.Packets;
|
||||
using MQTTnet.Protocol;
|
||||
using MQTTnet.Server;
|
||||
using MQTTnet.Server.EnhancedAuthentication;
|
||||
@@ -143,7 +144,7 @@ public sealed class MqttClient_Connection_Tests : BaseTestClass
|
||||
|
||||
var client = await testEnvironment.ConnectClient();
|
||||
|
||||
var disconnectOptions = testEnvironment.ClientFactory.CreateClientDisconnectOptionsBuilder().WithUserProperty("test_name", "test_value").Build();
|
||||
var disconnectOptions = testEnvironment.ClientFactory.CreateClientDisconnectOptionsBuilder().WithUserProperty("test_name", Encoding.UTF8.GetBytes("test_value")).Build();
|
||||
|
||||
// Perform a clean disconnect.
|
||||
await client.DisconnectAsync(disconnectOptions);
|
||||
@@ -154,7 +155,7 @@ public sealed class MqttClient_Connection_Tests : BaseTestClass
|
||||
Assert.IsNotNull(eventArgs.UserProperties);
|
||||
Assert.HasCount(1, eventArgs.UserProperties);
|
||||
Assert.AreEqual("test_name", eventArgs.UserProperties[0].Name);
|
||||
Assert.AreEqual("test_value", eventArgs.UserProperties[0].Value);
|
||||
Assert.AreEqual("test_value", eventArgs.UserProperties[0].ReadValueAsString());
|
||||
}
|
||||
|
||||
sealed class TestClientKerberosAuthenticationHandler : IMqttEnhancedAuthenticationHandler
|
||||
@@ -260,7 +261,7 @@ public sealed class MqttClient_Connection_Tests : BaseTestClass
|
||||
|
||||
server.ValidatingConnectionAsync += args =>
|
||||
{
|
||||
args.ResponseUserProperties = [new("Property", "Value")];
|
||||
args.ResponseUserProperties = [new("Property", Encoding.UTF8.GetBytes("Value"))];
|
||||
|
||||
args.ReasonCode = MqttConnectReasonCode.QuotaExceeded;
|
||||
|
||||
@@ -274,7 +275,7 @@ public sealed class MqttClient_Connection_Tests : BaseTestClass
|
||||
Assert.IsNotNull(response);
|
||||
Assert.AreEqual(MqttClientConnectResultCode.QuotaExceeded, response.ResultCode);
|
||||
Assert.AreEqual("Property", response.UserProperties[0].Name);
|
||||
Assert.AreEqual("Value", response.UserProperties[0].Value);
|
||||
Assert.AreEqual("Value", response.UserProperties[0].ReadValueAsString());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Buffers;
|
||||
using System.Text;
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Packets;
|
||||
@@ -45,7 +46,7 @@ public sealed class MqttPacketSerialization_V3_Tests
|
||||
SubscriptionIdentifiersAvailable = true,
|
||||
TopicAliasMaximum = 963,
|
||||
WildcardSubscriptionAvailable = true,
|
||||
UserProperties = [new("Foo", "Bar")]
|
||||
UserProperties = [new("Foo", Encoding.UTF8.GetBytes("Bar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(connAckPacket, MqttProtocolVersion.V311);
|
||||
@@ -96,7 +97,7 @@ public sealed class MqttPacketSerialization_V3_Tests
|
||||
SubscriptionIdentifiersAvailable = true,
|
||||
TopicAliasMaximum = 963,
|
||||
WildcardSubscriptionAvailable = true,
|
||||
UserProperties = [new MqttUserProperty("Foo", "Bar")]
|
||||
UserProperties = [new MqttUserProperty("Foo", Encoding.UTF8.GetBytes("Bar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(connAckPacket, MqttProtocolVersion.V310);
|
||||
@@ -152,8 +153,8 @@ public sealed class MqttPacketSerialization_V3_Tests
|
||||
WillResponseTopic = "WillResponseTopic",
|
||||
WillMessageExpiryInterval = 542,
|
||||
WillPayloadFormatIndicator = MqttPayloadFormatIndicator.CharacterData,
|
||||
UserProperties = [new("Foo", "Bar")],
|
||||
WillUserProperties = [new("WillFoo", "WillBar")]
|
||||
UserProperties = [new("Foo", Encoding.UTF8.GetBytes("Bar"))],
|
||||
WillUserProperties = [new("WillFoo", Encoding.UTF8.GetBytes("WillBar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(connectPacket, MqttProtocolVersion.V311);
|
||||
@@ -195,7 +196,7 @@ public sealed class MqttPacketSerialization_V3_Tests
|
||||
ReasonString = "ReasonString",
|
||||
ServerReference = "ServerReference",
|
||||
SessionExpiryInterval = 234,
|
||||
UserProperties = [new("Foo", "Bar")]
|
||||
UserProperties = [new("Foo", Encoding.UTF8.GetBytes("Bar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(disconnectPacket, MqttProtocolVersion.V311);
|
||||
@@ -235,7 +236,7 @@ public sealed class MqttPacketSerialization_V3_Tests
|
||||
PacketIdentifier = 123,
|
||||
ReasonCode = MqttPubAckReasonCode.NoMatchingSubscribers,
|
||||
ReasonString = "ReasonString",
|
||||
UserProperties = [new("Foo", "Bar")]
|
||||
UserProperties = [new("Foo", Encoding.UTF8.GetBytes("Bar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(pubAckPacket, MqttProtocolVersion.V311);
|
||||
@@ -254,7 +255,7 @@ public sealed class MqttPacketSerialization_V3_Tests
|
||||
PacketIdentifier = 123,
|
||||
ReasonCode = MqttPubCompReasonCode.PacketIdentifierNotFound,
|
||||
ReasonString = "ReasonString",
|
||||
UserProperties = [new("Foo", "Bar")]
|
||||
UserProperties = [new("Foo", Encoding.UTF8.GetBytes("Bar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(pubCompPacket, MqttProtocolVersion.V311);
|
||||
@@ -284,7 +285,7 @@ public sealed class MqttPacketSerialization_V3_Tests
|
||||
SubscriptionIdentifiers = [123],
|
||||
MessageExpiryInterval = 38,
|
||||
PayloadFormatIndicator = MqttPayloadFormatIndicator.CharacterData,
|
||||
UserProperties = [new("Foo", "Bar")]
|
||||
UserProperties = [new("Foo", Encoding.UTF8.GetBytes("Bar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(publishPacket, MqttProtocolVersion.V311);
|
||||
@@ -313,7 +314,7 @@ public sealed class MqttPacketSerialization_V3_Tests
|
||||
PacketIdentifier = 123,
|
||||
ReasonCode = MqttPubRecReasonCode.UnspecifiedError,
|
||||
ReasonString = "ReasonString",
|
||||
UserProperties = [new("Foo", "Bar")]
|
||||
UserProperties = [new("Foo", Encoding.UTF8.GetBytes("Bar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(pubRecPacket, MqttProtocolVersion.V311);
|
||||
@@ -333,7 +334,7 @@ public sealed class MqttPacketSerialization_V3_Tests
|
||||
PacketIdentifier = 123,
|
||||
ReasonCode = MqttPubRelReasonCode.PacketIdentifierNotFound,
|
||||
ReasonString = "ReasonString",
|
||||
UserProperties = [new("Foo", "Bar")]
|
||||
UserProperties = [new("Foo", Encoding.UTF8.GetBytes("Bar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(pubRelPacket, MqttProtocolVersion.V311);
|
||||
@@ -353,7 +354,7 @@ public sealed class MqttPacketSerialization_V3_Tests
|
||||
PacketIdentifier = 123,
|
||||
ReasonString = "ReasonString",
|
||||
ReasonCodes = [MqttSubscribeReasonCode.GrantedQoS1],
|
||||
UserProperties = [new("Foo", "Bar")]
|
||||
UserProperties = [new("Foo", Encoding.UTF8.GetBytes("Bar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(subAckPacket, MqttProtocolVersion.V311);
|
||||
@@ -383,7 +384,7 @@ public sealed class MqttPacketSerialization_V3_Tests
|
||||
QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce
|
||||
}
|
||||
],
|
||||
UserProperties = [new("Foo", "Bar")]
|
||||
UserProperties = [new("Foo", Encoding.UTF8.GetBytes("Bar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(subscribePacket, MqttProtocolVersion.V311);
|
||||
@@ -407,7 +408,7 @@ public sealed class MqttPacketSerialization_V3_Tests
|
||||
PacketIdentifier = 123,
|
||||
ReasonCodes = [MqttUnsubscribeReasonCode.ImplementationSpecificError],
|
||||
ReasonString = "ReasonString",
|
||||
UserProperties = [new("Foo", "Bar")]
|
||||
UserProperties = [new("Foo", Encoding.UTF8.GetBytes("Bar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(unsubAckPacket, MqttProtocolVersion.V311);
|
||||
@@ -425,7 +426,7 @@ public sealed class MqttPacketSerialization_V3_Tests
|
||||
{
|
||||
PacketIdentifier = 123,
|
||||
TopicFilters = ["TopicFilter1"],
|
||||
UserProperties = [new("Foo", "Bar")]
|
||||
UserProperties = [new("Foo", Encoding.UTF8.GetBytes("Bar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(unsubscribePacket, MqttProtocolVersion.V311);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Buffers;
|
||||
using System.Text;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Packets;
|
||||
using MQTTnet.Protocol;
|
||||
@@ -32,7 +33,7 @@ public sealed class MqttPacketSerialization_V5_Tests
|
||||
AuthenticationMethod = "AuthenticationMethod",
|
||||
ReasonCode = MqttAuthenticateReasonCode.ContinueAuthentication,
|
||||
ReasonString = "ReasonString",
|
||||
UserProperties = [new MqttUserProperty("Foo", "Bar")]
|
||||
UserProperties = [new MqttUserProperty("Foo", Encoding.UTF8.GetBytes("Bar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(authPacket, MqttProtocolVersion.V500);
|
||||
@@ -68,7 +69,7 @@ public sealed class MqttPacketSerialization_V5_Tests
|
||||
SubscriptionIdentifiersAvailable = true,
|
||||
TopicAliasMaximum = 963,
|
||||
WildcardSubscriptionAvailable = true,
|
||||
UserProperties = [new MqttUserProperty("Foo", "Bar")]
|
||||
UserProperties = [new MqttUserProperty("Foo", Encoding.UTF8.GetBytes("Bar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(connAckPacket, MqttProtocolVersion.V500);
|
||||
@@ -124,8 +125,8 @@ public sealed class MqttPacketSerialization_V5_Tests
|
||||
WillResponseTopic = "WillResponseTopic",
|
||||
WillMessageExpiryInterval = 542,
|
||||
WillPayloadFormatIndicator = MqttPayloadFormatIndicator.CharacterData,
|
||||
UserProperties = [new MqttUserProperty("Foo", "Bar")],
|
||||
WillUserProperties = [new MqttUserProperty("WillFoo", "WillBar")]
|
||||
UserProperties = [new MqttUserProperty("Foo", Encoding.UTF8.GetBytes("Bar"))],
|
||||
WillUserProperties = [new MqttUserProperty("WillFoo", Encoding.UTF8.GetBytes("WillBar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(connectPacket, MqttProtocolVersion.V500);
|
||||
@@ -167,7 +168,7 @@ public sealed class MqttPacketSerialization_V5_Tests
|
||||
ReasonString = "ReasonString",
|
||||
ServerReference = "ServerReference",
|
||||
SessionExpiryInterval = 234,
|
||||
UserProperties = [new MqttUserProperty("Foo", "Bar")]
|
||||
UserProperties = [new MqttUserProperty("Foo", Encoding.UTF8.GetBytes("Bar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(disconnectPacket, MqttProtocolVersion.V500);
|
||||
@@ -207,7 +208,7 @@ public sealed class MqttPacketSerialization_V5_Tests
|
||||
PacketIdentifier = 123,
|
||||
ReasonCode = MqttPubAckReasonCode.NoMatchingSubscribers,
|
||||
ReasonString = "ReasonString",
|
||||
UserProperties = [new MqttUserProperty("Foo", "Bar")]
|
||||
UserProperties = [new MqttUserProperty("Foo", Encoding.UTF8.GetBytes("Bar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(pubAckPacket, MqttProtocolVersion.V500);
|
||||
@@ -226,7 +227,7 @@ public sealed class MqttPacketSerialization_V5_Tests
|
||||
PacketIdentifier = 123,
|
||||
ReasonCode = MqttPubCompReasonCode.PacketIdentifierNotFound,
|
||||
ReasonString = "ReasonString",
|
||||
UserProperties = [new MqttUserProperty("Foo", "Bar")]
|
||||
UserProperties = [new MqttUserProperty("Foo", Encoding.UTF8.GetBytes("Bar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(pubCompPacket, MqttProtocolVersion.V500);
|
||||
@@ -255,7 +256,7 @@ public sealed class MqttPacketSerialization_V5_Tests
|
||||
SubscriptionIdentifiers = [123],
|
||||
MessageExpiryInterval = 38,
|
||||
PayloadFormatIndicator = MqttPayloadFormatIndicator.CharacterData,
|
||||
UserProperties = [new MqttUserProperty("Foo", "Bar")]
|
||||
UserProperties = [new MqttUserProperty("Foo", Encoding.UTF8.GetBytes("Bar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(publishPacket, MqttProtocolVersion.V500);
|
||||
@@ -284,7 +285,7 @@ public sealed class MqttPacketSerialization_V5_Tests
|
||||
PacketIdentifier = 123,
|
||||
ReasonCode = MqttPubRecReasonCode.UnspecifiedError,
|
||||
ReasonString = "ReasonString",
|
||||
UserProperties = [new MqttUserProperty("Foo", "Bar")]
|
||||
UserProperties = [new MqttUserProperty("Foo", Encoding.UTF8.GetBytes("Bar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(pubRecPacket, MqttProtocolVersion.V500);
|
||||
@@ -303,7 +304,7 @@ public sealed class MqttPacketSerialization_V5_Tests
|
||||
PacketIdentifier = 123,
|
||||
ReasonCode = MqttPubRelReasonCode.PacketIdentifierNotFound,
|
||||
ReasonString = "ReasonString",
|
||||
UserProperties = [new MqttUserProperty("Foo", "Bar")]
|
||||
UserProperties = [new MqttUserProperty("Foo", Encoding.UTF8.GetBytes("Bar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(pubRelPacket, MqttProtocolVersion.V500);
|
||||
@@ -322,7 +323,7 @@ public sealed class MqttPacketSerialization_V5_Tests
|
||||
PacketIdentifier = 123,
|
||||
ReasonString = "ReasonString",
|
||||
ReasonCodes = [MqttSubscribeReasonCode.GrantedQoS1],
|
||||
UserProperties = [new MqttUserProperty("Foo", "Bar")]
|
||||
UserProperties = [new MqttUserProperty("Foo", Encoding.UTF8.GetBytes("Bar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(subAckPacket, MqttProtocolVersion.V500);
|
||||
@@ -352,7 +353,7 @@ public sealed class MqttPacketSerialization_V5_Tests
|
||||
QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce
|
||||
}
|
||||
],
|
||||
UserProperties = [new MqttUserProperty("Foo", "Bar")]
|
||||
UserProperties = [new MqttUserProperty("Foo", Encoding.UTF8.GetBytes("Bar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(subscribePacket, MqttProtocolVersion.V500);
|
||||
@@ -376,7 +377,7 @@ public sealed class MqttPacketSerialization_V5_Tests
|
||||
PacketIdentifier = 123,
|
||||
ReasonCodes = [MqttUnsubscribeReasonCode.ImplementationSpecificError],
|
||||
ReasonString = "ReasonString",
|
||||
UserProperties = [new MqttUserProperty("Foo", "Bar")]
|
||||
UserProperties = [new MqttUserProperty("Foo", Encoding.UTF8.GetBytes("Bar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(unsubAckPacket, MqttProtocolVersion.V500);
|
||||
@@ -395,7 +396,7 @@ public sealed class MqttPacketSerialization_V5_Tests
|
||||
{
|
||||
PacketIdentifier = 123,
|
||||
TopicFilters = ["TopicFilter1"],
|
||||
UserProperties = [new MqttUserProperty("Foo", "Bar")]
|
||||
UserProperties = [new MqttUserProperty("Foo", Encoding.UTF8.GetBytes("Bar"))]
|
||||
};
|
||||
|
||||
var deserialized = MqttPacketSerializationHelper.EncodeAndDecodePacket(unsubscribePacket, MqttProtocolVersion.V500);
|
||||
|
||||
@@ -6,13 +6,12 @@
|
||||
<LangVersion>default</LangVersion>
|
||||
<Nullable>disable</Nullable>
|
||||
<NoWarn>$(NoWarn);CA1707</NoWarn>
|
||||
<EnableMSTestRunner>true</EnableMSTestRunner>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.0" />
|
||||
<PackageReference Include="MSTest" Version="4.0.1" />
|
||||
|
||||
<PackageReference Include="MSTest" Version="4.0.2" />
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -24,4 +23,10 @@
|
||||
<ProjectReference Include="..\MQTTnet.Extensions.TopicTemplate\MQTTnet.Extensions.TopicTemplate.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<None Include=".\..\..\global.json"
|
||||
Link="global.json"
|
||||
CopyToOutputDirectory="PreserveNewest"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
using System.Buffers;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
using Microsoft.IO;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Internal;
|
||||
@@ -64,8 +65,8 @@ public sealed class Client_Tests : BaseTestClass
|
||||
await client.PublishAsync(
|
||||
new MqttApplicationMessageBuilder().WithTopic("a")
|
||||
.WithPayload("x")
|
||||
.WithUserProperty("a", "1")
|
||||
.WithUserProperty("b", "2")
|
||||
.WithUserProperty("a", Encoding.UTF8.GetBytes("1"))
|
||||
.WithUserProperty("b", Encoding.UTF8.GetBytes("2"))
|
||||
.WithPayloadFormatIndicator(MqttPayloadFormatIndicator.CharacterData)
|
||||
.WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtLeastOnce)
|
||||
.Build());
|
||||
@@ -98,8 +99,8 @@ public sealed class Client_Tests : BaseTestClass
|
||||
var applicationMessage = new MqttApplicationMessageBuilder().WithTopic("Hello")
|
||||
.WithPayload("World")
|
||||
.WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtMostOnce)
|
||||
.WithUserProperty("x", "1")
|
||||
.WithUserProperty("y", "2")
|
||||
.WithUserProperty("x", Encoding.UTF8.GetBytes("1"))
|
||||
.WithUserProperty("y", Encoding.UTF8.GetBytes("2"))
|
||||
.WithResponseTopic("response")
|
||||
.WithContentType("text")
|
||||
.WithMessageExpiryInterval(50)
|
||||
@@ -214,8 +215,8 @@ public sealed class Client_Tests : BaseTestClass
|
||||
var applicationMessage = new MqttApplicationMessageBuilder().WithTopic("Hello")
|
||||
.WithPayload("World")
|
||||
.WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtMostOnce)
|
||||
.WithUserProperty("x", "1")
|
||||
.WithUserProperty("y", "2")
|
||||
.WithUserProperty("x", Encoding.UTF8.GetBytes("1"))
|
||||
.WithUserProperty("y", Encoding.UTF8.GetBytes("2"))
|
||||
.WithResponseTopic("response")
|
||||
.WithContentType("text")
|
||||
.WithMessageExpiryInterval(50)
|
||||
@@ -250,8 +251,8 @@ public sealed class Client_Tests : BaseTestClass
|
||||
var applicationMessage = new MqttApplicationMessageBuilder().WithTopic("Hello")
|
||||
.WithPayload(memoryStream.GetReadOnlySequence())
|
||||
.WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtMostOnce)
|
||||
.WithUserProperty("x", "1")
|
||||
.WithUserProperty("y", "2")
|
||||
.WithUserProperty("x", Encoding.UTF8.GetBytes("1"))
|
||||
.WithUserProperty("y", Encoding.UTF8.GetBytes("2"))
|
||||
.WithResponseTopic("response")
|
||||
.WithContentType("text")
|
||||
.WithMessageExpiryInterval(50)
|
||||
|
||||
@@ -2,7 +2,12 @@
|
||||
// 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.Text;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Formatter.V5;
|
||||
using MQTTnet.Packets;
|
||||
using MQTTnet.Protocol;
|
||||
|
||||
namespace MQTTnet.Tests;
|
||||
@@ -59,4 +64,64 @@ public sealed class MqttApplicationMessageBuilder_Tests
|
||||
Assert.IsTrue(message.Retain);
|
||||
Assert.AreEqual(MqttQualityOfServiceLevel.ExactlyOnce, message.QualityOfServiceLevel);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CreateApplicationMessage_UserProperty_ReadOnlyMemoryValue()
|
||||
{
|
||||
var value = "utf8";
|
||||
var buffer = Encoding.UTF8.GetBytes(value);
|
||||
|
||||
var message = new MqttApplicationMessageBuilder().WithTopic("topic").WithUserProperty("name", buffer.AsMemory()).Build();
|
||||
|
||||
Assert.IsNotNull(message.UserProperties);
|
||||
Assert.HasCount(1, message.UserProperties);
|
||||
|
||||
var userProperty = message.UserProperties[0];
|
||||
CollectionAssert.AreEqual(buffer, userProperty.ValueBuffer.ToArray());
|
||||
Assert.AreEqual(value, userProperty.ReadValueAsString());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CreateApplicationMessage_UserProperty_ArraySegmentValue()
|
||||
{
|
||||
var buffer = Encoding.UTF8.GetBytes("segment");
|
||||
var segment = new ArraySegment<byte>(buffer);
|
||||
|
||||
var message = new MqttApplicationMessageBuilder().WithTopic("topic").WithUserProperty("name", segment).Build();
|
||||
|
||||
Assert.IsNotNull(message.UserProperties);
|
||||
Assert.HasCount(1, message.UserProperties);
|
||||
|
||||
var userProperty = message.UserProperties[0];
|
||||
CollectionAssert.AreEqual(buffer, userProperty.ValueBuffer.ToArray());
|
||||
Assert.AreEqual("segment", userProperty.ReadValueAsString());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WriteUserProperty_FromBinaryBuffer_EqualsStringEncoding()
|
||||
{
|
||||
var name = "name";
|
||||
var value = "value";
|
||||
var encoded = Encoding.UTF8.GetBytes(value);
|
||||
|
||||
var binaryWriter = new MqttBufferWriter(32, 256);
|
||||
var binaryPropertiesWriter = new MqttV5PropertiesWriter(binaryWriter);
|
||||
binaryPropertiesWriter.WriteUserProperties(new List<MqttUserProperty> { new(name, encoded.AsMemory()) });
|
||||
|
||||
var stringWriter = new MqttBufferWriter(32, 256);
|
||||
var stringPropertiesWriter = new MqttV5PropertiesWriter(stringWriter);
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
stringPropertiesWriter.WriteUserProperties(new List<MqttUserProperty> { new(name, value) });
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
|
||||
CollectionAssert.AreEqual(GetWrittenBytes(stringWriter), GetWrittenBytes(binaryWriter));
|
||||
}
|
||||
|
||||
static byte[] GetWrittenBytes(MqttBufferWriter writer)
|
||||
{
|
||||
var length = writer.Length;
|
||||
var copy = new byte[length];
|
||||
Array.Copy(writer.GetBuffer(), copy, length);
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
// 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.Text;
|
||||
using MQTTnet.Formatter;
|
||||
|
||||
namespace MQTTnet.Tests;
|
||||
@@ -27,7 +28,7 @@ public sealed class MqttApplicationMessageValidator_Tests
|
||||
public void Succeed_When_Using_UserProperties_And_MQTT_500()
|
||||
{
|
||||
MqttApplicationMessageValidator.ThrowIfNotSupported(
|
||||
new MqttApplicationMessageBuilder().WithTopic("A").WithUserProperty("User", "Property").Build(),
|
||||
new MqttApplicationMessageBuilder().WithTopic("A").WithUserProperty("User", Encoding.UTF8.GetBytes("Property")).Build(),
|
||||
MqttProtocolVersion.V500);
|
||||
}
|
||||
|
||||
@@ -35,7 +36,7 @@ public sealed class MqttApplicationMessageValidator_Tests
|
||||
public void Succeed_When_Using_WillUserProperties_And_MQTT_311()
|
||||
{
|
||||
Assert.ThrowsExactly<NotSupportedException>(() => MqttApplicationMessageValidator.ThrowIfNotSupported(
|
||||
new MqttApplicationMessageBuilder().WithTopic("B").WithUserProperty("User", "Property").Build(),
|
||||
new MqttApplicationMessageBuilder().WithTopic("B").WithUserProperty("User", Encoding.UTF8.GetBytes("Property")).Build(),
|
||||
MqttProtocolVersion.V311));
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
// 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.Text;
|
||||
using MQTTnet.Formatter;
|
||||
|
||||
namespace MQTTnet.Tests;
|
||||
@@ -13,27 +14,27 @@ public sealed class MqttClientOptionsValidator_Tests
|
||||
[TestMethod]
|
||||
public void Succeed_When_Using_UserProperties_And_MQTT_500()
|
||||
{
|
||||
new MqttClientOptionsBuilder().WithProtocolVersion(MqttProtocolVersion.V500).WithUserProperty("User", "Property").WithTcpServer("FAKE").Build();
|
||||
new MqttClientOptionsBuilder().WithProtocolVersion(MqttProtocolVersion.V500).WithUserProperty("User", Encoding.UTF8.GetBytes("Property")).WithTcpServer("FAKE").Build();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Succeed_When_Using_WillUserProperties_And_MQTT_311()
|
||||
{
|
||||
Assert.ThrowsExactly<NotSupportedException>(() =>
|
||||
new MqttClientOptionsBuilder().WithProtocolVersion(MqttProtocolVersion.V311).WithWillUserProperty("User", "Property").WithTcpServer("FAKE").Build());
|
||||
new MqttClientOptionsBuilder().WithProtocolVersion(MqttProtocolVersion.V311).WithWillUserProperty("User", Encoding.UTF8.GetBytes("Property")).WithTcpServer("FAKE").Build());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Succeed_When_Using_WillUserProperties_And_MQTT_500()
|
||||
{
|
||||
new MqttClientOptionsBuilder().WithProtocolVersion(MqttProtocolVersion.V500).WithWillUserProperty("User", "Property").WithTcpServer("FAKE").Build();
|
||||
new MqttClientOptionsBuilder().WithProtocolVersion(MqttProtocolVersion.V500).WithWillUserProperty("User", Encoding.UTF8.GetBytes("Property")).WithTcpServer("FAKE").Build();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Throw_When_Using_UserProperties_And_MQTT_311()
|
||||
{
|
||||
Assert.ThrowsExactly<NotSupportedException>(() =>
|
||||
new MqttClientOptionsBuilder().WithProtocolVersion(MqttProtocolVersion.V311).WithUserProperty("User", "Property").WithTcpServer("FAKE").Build());
|
||||
new MqttClientOptionsBuilder().WithProtocolVersion(MqttProtocolVersion.V311).WithUserProperty("User", Encoding.UTF8.GetBytes("Property")).WithTcpServer("FAKE").Build());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
||||
@@ -20,7 +20,8 @@ public class MqttTcpChannel_Tests
|
||||
|
||||
try
|
||||
{
|
||||
serverSocket.Bind(new IPEndPoint(IPAddress.Any, 50001));
|
||||
serverSocket.Bind(new IPEndPoint(IPAddress.Loopback, 0));
|
||||
var serverPort = ((IPEndPoint)serverSocket.LocalEndPoint).Port;
|
||||
serverSocket.Listen(0);
|
||||
|
||||
#pragma warning disable 4014
|
||||
@@ -37,7 +38,7 @@ public class MqttTcpChannel_Tests
|
||||
},
|
||||
ct.Token);
|
||||
|
||||
var remoteEndPoint = new DnsEndPoint("localhost", 50001);
|
||||
var remoteEndPoint = new DnsEndPoint("localhost", serverPort);
|
||||
using var clientSocket = new CrossPlatformSocket(AddressFamily.InterNetwork, ProtocolType.Tcp);
|
||||
await clientSocket.ConnectAsync(remoteEndPoint, CancellationToken.None);
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ public sealed class Cross_Version_Tests : BaseTestClass
|
||||
|
||||
var applicationMessage = new MqttApplicationMessageBuilder().WithTopic("My/Message")
|
||||
.WithPayload("My_Payload")
|
||||
.WithUserProperty("A", "B")
|
||||
.WithUserProperty("A", Encoding.UTF8.GetBytes("B"))
|
||||
.WithResponseTopic("Response")
|
||||
.WithCorrelationData(Encoding.UTF8.GetBytes("Correlation"))
|
||||
.Build();
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Net.Security;
|
||||
using System.Net.Sockets;
|
||||
using System.Security.Authentication;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
@@ -26,6 +27,7 @@ public sealed class HotSwapCerts_Tests
|
||||
using var client01 = new ClientTestHarness();
|
||||
server.InstallNewClientCert(client01.GetCurrentClientCert());
|
||||
client01.InstallNewServerCert(server.GetCurrentServerCert());
|
||||
client01.SetServerPort(server.EncryptedPort);
|
||||
|
||||
await server.StartServer();
|
||||
|
||||
@@ -47,6 +49,7 @@ public sealed class HotSwapCerts_Tests
|
||||
using var client01 = new ClientTestHarness();
|
||||
server.InstallNewClientCert(client01.GetCurrentClientCert());
|
||||
client01.InstallNewServerCert(server.GetCurrentServerCert());
|
||||
client01.SetServerPort(server.EncryptedPort);
|
||||
|
||||
await server.StartServer();
|
||||
|
||||
@@ -70,6 +73,7 @@ public sealed class HotSwapCerts_Tests
|
||||
using var client01 = new ClientTestHarness();
|
||||
server.InstallNewClientCert(client01.GetCurrentClientCert());
|
||||
client01.InstallNewServerCert(server.GetCurrentServerCert());
|
||||
client01.SetServerPort(server.EncryptedPort);
|
||||
|
||||
await server.StartServer();
|
||||
await client01.Connect();
|
||||
@@ -91,6 +95,7 @@ public sealed class HotSwapCerts_Tests
|
||||
using var client01 = new ClientTestHarness();
|
||||
server.InstallNewClientCert(client01.GetCurrentClientCert());
|
||||
client01.InstallNewServerCert(server.GetCurrentServerCert());
|
||||
client01.SetServerPort(server.EncryptedPort);
|
||||
|
||||
await server.StartServer();
|
||||
await client01.Connect();
|
||||
@@ -135,10 +140,11 @@ public sealed class HotSwapCerts_Tests
|
||||
sealed class ClientTestHarness : IDisposable
|
||||
{
|
||||
readonly HotSwappableClientCertProvider _hotSwapClient = new HotSwappableClientCertProvider();
|
||||
int _serverPort = 8883;
|
||||
|
||||
IMqttClient _client;
|
||||
|
||||
public string ClientId => _client.Options.ClientId;
|
||||
public string ClientId => _client?.Options?.ClientId;
|
||||
|
||||
public Task Connect()
|
||||
{
|
||||
@@ -147,10 +153,15 @@ public sealed class HotSwapCerts_Tests
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_client.Dispose();
|
||||
_client?.Dispose();
|
||||
_hotSwapClient.Dispose();
|
||||
}
|
||||
|
||||
public void SetServerPort(int port)
|
||||
{
|
||||
_serverPort = port;
|
||||
}
|
||||
|
||||
public X509Certificate2 GetCurrentClientCert()
|
||||
{
|
||||
var result = _hotSwapClient.GetCertificates()[0];
|
||||
@@ -216,7 +227,7 @@ public sealed class HotSwapCerts_Tests
|
||||
o => o.WithClientCertificatesProvider(_hotSwapClient)
|
||||
.WithCertificateValidationHandler(_hotSwapClient.OnCertificateValidation)
|
||||
.WithSslProtocols(SslProtocols.Tls12))
|
||||
.WithTcpServer("localhost")
|
||||
.WithTcpServer("localhost", _serverPort)
|
||||
.WithCleanSession()
|
||||
.WithProtocolVersion(MqttProtocolVersion.V500);
|
||||
|
||||
@@ -242,6 +253,7 @@ public sealed class HotSwapCerts_Tests
|
||||
sealed class ServerTestHarness : IDisposable
|
||||
{
|
||||
readonly HotSwappableServerCertProvider _hotSwapServer = new HotSwappableServerCertProvider();
|
||||
readonly int _encryptedPort = GetFreeTcpPort();
|
||||
|
||||
MqttServer _server;
|
||||
|
||||
@@ -261,6 +273,8 @@ public sealed class HotSwapCerts_Tests
|
||||
return _server.DisconnectClientAsync(client.ClientId, MqttDisconnectReasonCode.UnspecifiedError);
|
||||
}
|
||||
|
||||
public int EncryptedPort => _encryptedPort;
|
||||
|
||||
public X509Certificate2 GetCurrentServerCert()
|
||||
{
|
||||
return _hotSwapServer.GetCertificate();
|
||||
@@ -281,6 +295,7 @@ public sealed class HotSwapCerts_Tests
|
||||
var mqttServerFactory = new MqttServerFactory();
|
||||
|
||||
var mqttServerOptions = new MqttServerOptionsBuilder().WithEncryptionCertificate(_hotSwapServer)
|
||||
.WithEncryptedEndpointPort(_encryptedPort)
|
||||
.WithRemoteCertificateValidationCallback(_hotSwapServer.RemoteCertificateValidationCallback)
|
||||
.WithEncryptedEndpoint()
|
||||
.Build();
|
||||
@@ -290,6 +305,17 @@ public sealed class HotSwapCerts_Tests
|
||||
_server = mqttServerFactory.CreateMqttServer(mqttServerOptions);
|
||||
return _server.StartAsync();
|
||||
}
|
||||
|
||||
static int GetFreeTcpPort()
|
||||
{
|
||||
var listener = new TcpListener(IPAddress.Loopback, 0);
|
||||
listener.Start();
|
||||
|
||||
var port = ((IPEndPoint)listener.LocalEndpoint).Port;
|
||||
listener.Stop();
|
||||
|
||||
return port;
|
||||
}
|
||||
}
|
||||
|
||||
sealed class HotSwappableClientCertProvider : IMqttClientCertificatesProvider, IDisposable
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Internal;
|
||||
@@ -98,7 +99,7 @@ public sealed class Subscribe_Tests : BaseTestClass
|
||||
|
||||
var client = await testEnvironment.ConnectClient();
|
||||
|
||||
var subscribeOptions = testEnvironment.ClientFactory.CreateSubscribeOptionsBuilder().WithTopicFilter("X").WithUserProperty("A", "1").Build();
|
||||
var subscribeOptions = testEnvironment.ClientFactory.CreateSubscribeOptionsBuilder().WithTopicFilter("X").WithUserProperty("A", Encoding.UTF8.GetBytes("1")).Build();
|
||||
await client.SubscribeAsync(subscribeOptions);
|
||||
|
||||
CollectionAssert.AreEqual(subscribeOptions.UserProperties.ToList(), eventArgs.UserProperties);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using MQTTnet.Packets;
|
||||
using MQTTnet.Protocol;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// 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.Text;
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Internal;
|
||||
@@ -45,7 +46,7 @@ public sealed class Unsubscribe_Tests : BaseTestClass
|
||||
|
||||
var client = await testEnvironment.ConnectClient();
|
||||
|
||||
var unsubscribeOptions = testEnvironment.ClientFactory.CreateUnsubscribeOptionsBuilder().WithTopicFilter("X").WithUserProperty("A", "1").Build();
|
||||
var unsubscribeOptions = testEnvironment.ClientFactory.CreateUnsubscribeOptionsBuilder().WithTopicFilter("X").WithUserProperty("A", Encoding.UTF8.GetBytes("1")).Build();
|
||||
await client.UnsubscribeAsync(unsubscribeOptions);
|
||||
|
||||
CollectionAssert.AreEqual(unsubscribeOptions.UserProperties.ToList(), eventArgs.UserProperties);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// 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.Text;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Internal;
|
||||
using MQTTnet.Packets;
|
||||
@@ -26,10 +27,10 @@ public class Feature_Tests
|
||||
|
||||
var message = new MqttApplicationMessageBuilder()
|
||||
.WithTopic("A")
|
||||
.WithUserProperty("x", "1")
|
||||
.WithUserProperty("y", "2")
|
||||
.WithUserProperty("z", "3")
|
||||
.WithUserProperty("z", "4"); // z is here two times to test list of items
|
||||
.WithUserProperty("x", Encoding.UTF8.GetBytes("1"))
|
||||
.WithUserProperty("y", Encoding.UTF8.GetBytes("2"))
|
||||
.WithUserProperty("z", Encoding.UTF8.GetBytes("3"))
|
||||
.WithUserProperty("z", Encoding.UTF8.GetBytes("4")); // z is here two times to test list of items
|
||||
|
||||
await receiver.SubscribeAsync(new MqttClientSubscribeOptions
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user