You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

650 lines
20 KiB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading;
  7. using Microsoft.VisualStudio.TestTools.UnitTesting;
  8. using MQTTnet.Adapter;
  9. using MQTTnet.Formatter;
  10. using MQTTnet.Formatter.V3;
  11. using MQTTnet.Formatter.V5;
  12. using MQTTnet.Internal;
  13. using MQTTnet.Packets;
  14. using MQTTnet.Protocol;
  15. namespace MQTTnet.Tests
  16. {
  17. [TestClass]
  18. public class MqttPacketSerializer_Tests
  19. {
  20. [TestMethod]
  21. public void SerializeV310_MqttConnectPacket()
  22. {
  23. var p = new MqttConnectPacket
  24. {
  25. ClientId = "XYZ",
  26. Password = Encoding.UTF8.GetBytes("PASS"),
  27. Username = "USER",
  28. KeepAlivePeriod = 123,
  29. CleanSession = true
  30. };
  31. SerializeAndCompare(p, "EB0ABk1RSXNkcAPCAHsAA1hZWgAEVVNFUgAEUEFTUw==", MqttProtocolVersion.V310);
  32. }
  33. [TestMethod]
  34. public void SerializeV311_MqttConnectPacket()
  35. {
  36. var p = new MqttConnectPacket
  37. {
  38. ClientId = "XYZ",
  39. Password = Encoding.UTF8.GetBytes("PASS"),
  40. Username = "USER",
  41. KeepAlivePeriod = 123,
  42. CleanSession = true
  43. };
  44. SerializeAndCompare(p, "EBsABE1RVFQEwgB7AANYWVoABFVTRVIABFBBU1M=");
  45. }
  46. [TestMethod]
  47. public void SerializeV311_MqttConnectPacketWithWillMessage()
  48. {
  49. var p = new MqttConnectPacket
  50. {
  51. ClientId = "XYZ",
  52. Password = Encoding.UTF8.GetBytes("PASS"),
  53. Username = "USER",
  54. KeepAlivePeriod = 123,
  55. CleanSession = true,
  56. WillMessage = new MqttApplicationMessage
  57. {
  58. Topic = "My/last/will",
  59. Payload = Encoding.UTF8.GetBytes("Good byte."),
  60. QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce,
  61. Retain = true
  62. }
  63. };
  64. SerializeAndCompare(p, "EDUABE1RVFQE7gB7AANYWVoADE15L2xhc3Qvd2lsbAAKR29vZCBieXRlLgAEVVNFUgAEUEFTUw==");
  65. }
  66. [TestMethod]
  67. public void DeserializeV311_MqttConnectPacket()
  68. {
  69. var p = new MqttConnectPacket
  70. {
  71. ClientId = "XYZ",
  72. Password = Encoding.UTF8.GetBytes("PASS"),
  73. Username = "USER",
  74. KeepAlivePeriod = 123,
  75. CleanSession = true
  76. };
  77. DeserializeAndCompare(p, "EBsABE1RVFQEwgB7AANYWVoABFVTRVIABFBBU1M=");
  78. }
  79. [TestMethod]
  80. public void DeserializeV311_MqttConnectPacketWithWillMessage()
  81. {
  82. var p = new MqttConnectPacket
  83. {
  84. ClientId = "XYZ",
  85. Password = Encoding.UTF8.GetBytes("PASS"),
  86. Username = "USER",
  87. KeepAlivePeriod = 123,
  88. CleanSession = true,
  89. WillMessage = new MqttApplicationMessage
  90. {
  91. Topic = "My/last/will",
  92. Payload = Encoding.UTF8.GetBytes("Good byte."),
  93. QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce,
  94. Retain = true
  95. }
  96. };
  97. DeserializeAndCompare(p, "EDUABE1RVFQE7gB7AANYWVoADE15L2xhc3Qvd2lsbAAKR29vZCBieXRlLgAEVVNFUgAEUEFTUw==");
  98. }
  99. [TestMethod]
  100. public void SerializeV311_MqttConnAckPacket()
  101. {
  102. var p = new MqttConnAckPacket
  103. {
  104. IsSessionPresent = true,
  105. ReturnCode = MqttConnectReturnCode.ConnectionRefusedNotAuthorized
  106. };
  107. SerializeAndCompare(p, "IAIBBQ==");
  108. }
  109. [TestMethod]
  110. public void SerializeV310_MqttConnAckPacket()
  111. {
  112. var p = new MqttConnAckPacket
  113. {
  114. ReturnCode = MqttConnectReturnCode.ConnectionRefusedNotAuthorized
  115. };
  116. SerializeAndCompare(p, "IAIABQ==", MqttProtocolVersion.V310);
  117. }
  118. [TestMethod]
  119. public void DeserializeV311_MqttConnAckPacket()
  120. {
  121. var p = new MqttConnAckPacket
  122. {
  123. IsSessionPresent = true,
  124. ReturnCode = MqttConnectReturnCode.ConnectionRefusedNotAuthorized
  125. };
  126. DeserializeAndCompare(p, "IAIBBQ==");
  127. }
  128. [TestMethod]
  129. public void DeserializeV310_MqttConnAckPacket()
  130. {
  131. var p = new MqttConnAckPacket
  132. {
  133. ReturnCode = MqttConnectReturnCode.ConnectionRefusedNotAuthorized
  134. };
  135. DeserializeAndCompare(p, "IAIABQ==", MqttProtocolVersion.V310);
  136. }
  137. [TestMethod]
  138. public void Serialize_LargePacket()
  139. {
  140. var serializer = new MqttV311PacketFormatter();
  141. const int payloadLength = 80000;
  142. var payload = new byte[payloadLength];
  143. var value = 0;
  144. for (var i = 0; i < payloadLength; i++)
  145. {
  146. if (value > 255)
  147. {
  148. value = 0;
  149. }
  150. payload[i] = (byte)value;
  151. }
  152. var publishPacket = new MqttPublishPacket
  153. {
  154. Topic = "abcdefghijklmnopqrstuvwxyz0123456789",
  155. Payload = payload
  156. };
  157. var buffer = serializer.Encode(publishPacket);
  158. var testChannel = new TestMqttChannel(new MemoryStream(buffer.Array, buffer.Offset, buffer.Count));
  159. var header = new MqttPacketReader(testChannel).ReadFixedHeaderAsync(
  160. new byte[2],
  161. CancellationToken.None).GetAwaiter().GetResult().FixedHeader;
  162. var eof = buffer.Offset + buffer.Count;
  163. var receivedPacket = new ReceivedMqttPacket(
  164. header.Flags,
  165. new MqttPacketBodyReader(buffer.Array, eof - header.RemainingLength, buffer.Count + buffer.Offset),
  166. 0);
  167. var packet = (MqttPublishPacket)serializer.Decode(receivedPacket);
  168. Assert.AreEqual(publishPacket.Topic, packet.Topic);
  169. Assert.IsTrue(publishPacket.Payload.SequenceEqual(packet.Payload));
  170. }
  171. [TestMethod]
  172. public void SerializeV311_MqttDisconnectPacket()
  173. {
  174. SerializeAndCompare(new MqttDisconnectPacket(), "4AA=");
  175. }
  176. [TestMethod]
  177. public void SerializeV311_MqttPingReqPacket()
  178. {
  179. SerializeAndCompare(new MqttPingReqPacket(), "wAA=");
  180. }
  181. [TestMethod]
  182. public void SerializeV311_MqttPingRespPacket()
  183. {
  184. SerializeAndCompare(new MqttPingRespPacket(), "0AA=");
  185. }
  186. [TestMethod]
  187. public void SerializeV311_MqttPublishPacket()
  188. {
  189. var p = new MqttPublishPacket
  190. {
  191. PacketIdentifier = 123,
  192. Dup = true,
  193. Retain = true,
  194. Payload = Encoding.ASCII.GetBytes("HELLO"),
  195. QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce,
  196. Topic = "A/B/C"
  197. };
  198. SerializeAndCompare(p, "Ow4ABUEvQi9DAHtIRUxMTw==");
  199. }
  200. [TestMethod]
  201. public void SerializeV500_MqttPublishPacket()
  202. {
  203. var prop = new MqttPublishPacketProperties {UserProperties = new List<MqttUserProperty>()};
  204. prop.ResponseTopic = "/Response";
  205. prop.UserProperties.Add(new MqttUserProperty("Foo", "Bar"));
  206. var p = new MqttPublishPacket
  207. {
  208. PacketIdentifier = 123,
  209. Dup = true,
  210. Retain = true,
  211. Payload = Encoding.ASCII.GetBytes("HELLO"),
  212. QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce,
  213. Topic = "A/B/C",
  214. Properties = prop
  215. };
  216. var deserialized = Roundtrip(p, MqttProtocolVersion.V500);
  217. Assert.AreEqual(prop.ResponseTopic, deserialized.Properties.ResponseTopic);
  218. Assert.IsTrue(deserialized.Properties.UserProperties.Any(x => x.Name == "Foo"));
  219. }
  220. [TestMethod]
  221. public void SerializeV500_MqttPublishPacket_CorrelationData()
  222. {
  223. var data = "123456789";
  224. var req = new MqttApplicationMessageBuilder()
  225. .WithTopic("Foo")
  226. .WithResponseTopic($"_")
  227. .WithCorrelationData(Guid.NewGuid().ToByteArray())
  228. .WithPayload(data)
  229. .WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtMostOnce)
  230. .Build();
  231. var p = new MqttV500DataConverter().CreatePublishPacket(req);
  232. var deserialized = Roundtrip(p, MqttProtocolVersion.V500);
  233. Assert.IsTrue(p.Payload.SequenceEqual(deserialized.Payload));
  234. }
  235. [TestMethod]
  236. public void DeserializeV311_MqttPublishPacket()
  237. {
  238. var p = new MqttPublishPacket
  239. {
  240. PacketIdentifier = 123,
  241. Dup = true,
  242. Retain = true,
  243. Payload = Encoding.ASCII.GetBytes("HELLO"),
  244. QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce,
  245. Topic = "A/B/C"
  246. };
  247. DeserializeAndCompare(p, "Ow4ABUEvQi9DAHtIRUxMTw==");
  248. }
  249. [TestMethod]
  250. public void DeserializeV311_MqttPublishPacket_Qos1()
  251. {
  252. var p = new MqttPublishPacket
  253. {
  254. QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce,
  255. };
  256. var p2 = Roundtrip(p);
  257. Assert.AreEqual(p.QualityOfServiceLevel, p2.QualityOfServiceLevel);
  258. Assert.AreEqual(p.Dup, p2.Dup);
  259. }
  260. [TestMethod]
  261. public void DeserializeV311_MqttPublishPacket_Qos2()
  262. {
  263. var p = new MqttPublishPacket
  264. {
  265. QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce,
  266. PacketIdentifier = 1
  267. };
  268. var p2 = Roundtrip(p);
  269. Assert.AreEqual(p.QualityOfServiceLevel, p2.QualityOfServiceLevel);
  270. Assert.AreEqual(p.Dup, p2.Dup);
  271. }
  272. [TestMethod]
  273. public void DeserializeV311_MqttPublishPacket_Qos3()
  274. {
  275. var p = new MqttPublishPacket
  276. {
  277. QualityOfServiceLevel = MqttQualityOfServiceLevel.ExactlyOnce,
  278. PacketIdentifier = 1
  279. };
  280. var p2 = Roundtrip(p);
  281. Assert.AreEqual(p.QualityOfServiceLevel, p2.QualityOfServiceLevel);
  282. Assert.AreEqual(p.Dup, p2.Dup);
  283. }
  284. [TestMethod]
  285. public void DeserializeV311_MqttPublishPacket_DupFalse()
  286. {
  287. var p = new MqttPublishPacket
  288. {
  289. Dup = false,
  290. };
  291. var p2 = Roundtrip(p);
  292. Assert.AreEqual(p.Dup, p2.Dup);
  293. }
  294. [TestMethod]
  295. public void SerializeV311_MqttPubAckPacket()
  296. {
  297. var p = new MqttPubAckPacket
  298. {
  299. PacketIdentifier = 123
  300. };
  301. SerializeAndCompare(p, "QAIAew==");
  302. }
  303. [TestMethod]
  304. public void DeserializeV311_MqttPubAckPacket()
  305. {
  306. var p = new MqttPubAckPacket
  307. {
  308. PacketIdentifier = 123
  309. };
  310. DeserializeAndCompare(p, "QAIAew==");
  311. }
  312. [TestMethod]
  313. public void SerializeV311_MqttPubRecPacket()
  314. {
  315. var p = new MqttPubRecPacket
  316. {
  317. PacketIdentifier = 123
  318. };
  319. SerializeAndCompare(p, "UAIAew==");
  320. }
  321. [TestMethod]
  322. public void DeserializeV311_MqttPubRecPacket()
  323. {
  324. var p = new MqttPubRecPacket
  325. {
  326. PacketIdentifier = 123
  327. };
  328. DeserializeAndCompare(p, "UAIAew==");
  329. }
  330. [TestMethod]
  331. public void SerializeV311_MqttPubRelPacket()
  332. {
  333. var p = new MqttPubRelPacket
  334. {
  335. PacketIdentifier = 123
  336. };
  337. SerializeAndCompare(p, "YgIAew==");
  338. }
  339. [TestMethod]
  340. public void DeserializeV311_MqttPubRelPacket()
  341. {
  342. var p = new MqttPubRelPacket
  343. {
  344. PacketIdentifier = 123
  345. };
  346. DeserializeAndCompare(p, "YgIAew==");
  347. }
  348. [TestMethod]
  349. public void SerializeV311_MqttPubCompPacket()
  350. {
  351. var p = new MqttPubCompPacket
  352. {
  353. PacketIdentifier = 123
  354. };
  355. SerializeAndCompare(p, "cAIAew==");
  356. }
  357. [TestMethod]
  358. public void DeserializeV311_MqttPubCompPacket()
  359. {
  360. var p = new MqttPubCompPacket
  361. {
  362. PacketIdentifier = 123
  363. };
  364. DeserializeAndCompare(p, "cAIAew==");
  365. }
  366. [TestMethod]
  367. public void SerializeV311_MqttSubscribePacket()
  368. {
  369. var p = new MqttSubscribePacket
  370. {
  371. PacketIdentifier = 123
  372. };
  373. p.TopicFilters.Add(new TopicFilter { Topic = "A/B/C", QualityOfServiceLevel = MqttQualityOfServiceLevel.ExactlyOnce });
  374. p.TopicFilters.Add(new TopicFilter { Topic = "1/2/3", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce });
  375. p.TopicFilters.Add(new TopicFilter { Topic = "x/y/z", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce });
  376. SerializeAndCompare(p, "ghoAewAFQS9CL0MCAAUxLzIvMwEABXgveS96AA==");
  377. }
  378. [TestMethod]
  379. public void DeserializeV311_MqttSubscribePacket()
  380. {
  381. var p = new MqttSubscribePacket
  382. {
  383. PacketIdentifier = 123
  384. };
  385. p.TopicFilters.Add(new TopicFilter { Topic = "A/B/C", QualityOfServiceLevel = MqttQualityOfServiceLevel.ExactlyOnce });
  386. p.TopicFilters.Add(new TopicFilter { Topic = "1/2/3", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce });
  387. p.TopicFilters.Add(new TopicFilter { Topic = "x/y/z", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce });
  388. DeserializeAndCompare(p, "ghoAewAFQS9CL0MCAAUxLzIvMwEABXgveS96AA==");
  389. }
  390. [TestMethod]
  391. public void SerializeV311_MqttSubAckPacket()
  392. {
  393. var p = new MqttSubAckPacket
  394. {
  395. PacketIdentifier = 123
  396. };
  397. p.ReturnCodes.Add(MqttSubscribeReturnCode.SuccessMaximumQoS0);
  398. p.ReturnCodes.Add(MqttSubscribeReturnCode.SuccessMaximumQoS1);
  399. p.ReturnCodes.Add(MqttSubscribeReturnCode.SuccessMaximumQoS2);
  400. p.ReturnCodes.Add(MqttSubscribeReturnCode.Failure);
  401. SerializeAndCompare(p, "kAYAewABAoA=");
  402. }
  403. [TestMethod]
  404. public void DeserializeV311_MqttSubAckPacket()
  405. {
  406. var p = new MqttSubAckPacket
  407. {
  408. PacketIdentifier = 123
  409. };
  410. p.ReturnCodes.Add(MqttSubscribeReturnCode.SuccessMaximumQoS0);
  411. p.ReturnCodes.Add(MqttSubscribeReturnCode.SuccessMaximumQoS1);
  412. p.ReturnCodes.Add(MqttSubscribeReturnCode.SuccessMaximumQoS2);
  413. p.ReturnCodes.Add(MqttSubscribeReturnCode.Failure);
  414. DeserializeAndCompare(p, "kAYAewABAoA=");
  415. }
  416. [TestMethod]
  417. public void SerializeV311_MqttUnsubscribePacket()
  418. {
  419. var p = new MqttUnsubscribePacket
  420. {
  421. PacketIdentifier = 123
  422. };
  423. p.TopicFilters.Add("A/B/C");
  424. p.TopicFilters.Add("1/2/3");
  425. p.TopicFilters.Add("x/y/z");
  426. SerializeAndCompare(p, "ohcAewAFQS9CL0MABTEvMi8zAAV4L3kveg==");
  427. }
  428. [TestMethod]
  429. public void DeserializeV311_MqttUnsubscribePacket()
  430. {
  431. var p = new MqttUnsubscribePacket
  432. {
  433. PacketIdentifier = 123
  434. };
  435. p.TopicFilters.Add("A/B/C");
  436. p.TopicFilters.Add("1/2/3");
  437. p.TopicFilters.Add("x/y/z");
  438. DeserializeAndCompare(p, "ohcAewAFQS9CL0MABTEvMi8zAAV4L3kveg==");
  439. }
  440. [TestMethod]
  441. public void SerializeV311_MqttUnsubAckPacket()
  442. {
  443. var p = new MqttUnsubAckPacket
  444. {
  445. PacketIdentifier = 123
  446. };
  447. SerializeAndCompare(p, "sAIAew==");
  448. }
  449. [TestMethod]
  450. public void DeserializeV311_MqttUnsubAckPacket()
  451. {
  452. var p = new MqttUnsubAckPacket
  453. {
  454. PacketIdentifier = 123
  455. };
  456. DeserializeAndCompare(p, "sAIAew==");
  457. }
  458. private static void SerializeAndCompare(MqttBasePacket packet, string expectedBase64Value, MqttProtocolVersion protocolVersion = MqttProtocolVersion.V311)
  459. {
  460. IMqttPacketFormatter serializer;
  461. if (protocolVersion == MqttProtocolVersion.V311)
  462. {
  463. serializer = new MqttV311PacketFormatter();
  464. }
  465. else if (protocolVersion == MqttProtocolVersion.V310)
  466. {
  467. serializer = new MqttV310PacketFormatter();
  468. }
  469. else
  470. {
  471. throw new NotSupportedException();
  472. }
  473. var data = serializer.Encode(packet);
  474. Assert.AreEqual(expectedBase64Value, Convert.ToBase64String(Join(data)));
  475. }
  476. protected virtual IMqttPacketWriter WriterFactory()
  477. {
  478. return new MqttPacketWriter();
  479. }
  480. protected virtual IMqttPacketBodyReader ReaderFactory(byte[] data)
  481. {
  482. return new MqttPacketBodyReader(data, 0, data.Length);
  483. }
  484. private void DeserializeAndCompare(MqttBasePacket packet, string expectedBase64Value, MqttProtocolVersion protocolVersion = MqttProtocolVersion.V311)
  485. {
  486. var writer = WriterFactory();
  487. var serializer = MqttPacketFormatterAdapter.GetMqttPacketFormatter(protocolVersion, writer);
  488. var buffer1 = serializer.Encode(packet);
  489. using (var headerStream = new MemoryStream(Join(buffer1)))
  490. {
  491. var channel = new TestMqttChannel(headerStream);
  492. var fixedHeader = new byte[2];
  493. var header = new MqttPacketReader(channel).ReadFixedHeaderAsync(fixedHeader, CancellationToken.None).GetAwaiter().GetResult().FixedHeader;
  494. using (var bodyStream = new MemoryStream(Join(buffer1), (int)headerStream.Position, header.RemainingLength))
  495. {
  496. var reader = ReaderFactory(bodyStream.ToArray());
  497. var deserializedPacket = serializer.Decode(new ReceivedMqttPacket(header.Flags, reader, 0));
  498. var buffer2 = serializer.Encode(deserializedPacket);
  499. Assert.AreEqual(expectedBase64Value, Convert.ToBase64String(Join(buffer2)));
  500. }
  501. }
  502. }
  503. private T Roundtrip<T>(T packet, MqttProtocolVersion protocolVersion = MqttProtocolVersion.V311)
  504. where T : MqttBasePacket
  505. {
  506. var writer = WriterFactory();
  507. var serializer = MqttPacketFormatterAdapter.GetMqttPacketFormatter(protocolVersion, writer);
  508. var buffer1 = serializer.Encode(packet);
  509. using (var headerStream = new MemoryStream(Join(buffer1)))
  510. {
  511. var channel = new TestMqttChannel(headerStream);
  512. var fixedHeader = new byte[2];
  513. var header = new MqttPacketReader(channel).ReadFixedHeaderAsync(fixedHeader, CancellationToken.None).GetAwaiter().GetResult().FixedHeader;
  514. using (var bodyStream = new MemoryStream(Join(buffer1), (int)headerStream.Position, (int)header.RemainingLength))
  515. {
  516. var reader = ReaderFactory(bodyStream.ToArray());
  517. return (T)serializer.Decode(new ReceivedMqttPacket(header.Flags, reader, 0));
  518. }
  519. }
  520. }
  521. private static byte[] Join(params ArraySegment<byte>[] chunks)
  522. {
  523. var buffer = new MemoryStream();
  524. foreach (var chunk in chunks)
  525. {
  526. buffer.Write(chunk.Array, chunk.Offset, chunk.Count);
  527. }
  528. return buffer.ToArray();
  529. }
  530. }
  531. }