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.
 
 
 
 

496 lines
18 KiB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Net.Sockets;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. using Microsoft.VisualStudio.TestTools.UnitTesting;
  8. using MQTTnet.Client;
  9. using MQTTnet.Client.Connecting;
  10. using MQTTnet.Client.Disconnecting;
  11. using MQTTnet.Client.Options;
  12. using MQTTnet.Client.Subscribing;
  13. using MQTTnet.Exceptions;
  14. using MQTTnet.Protocol;
  15. using MQTTnet.Server;
  16. using MQTTnet.Tests.Mockups;
  17. namespace MQTTnet.Tests
  18. {
  19. [TestClass]
  20. public class Client_Tests
  21. {
  22. [TestMethod]
  23. public async Task Send_Reply_In_Message_Handler_For_Same_Client()
  24. {
  25. using (var testEnvironment = new TestEnvironment())
  26. {
  27. await testEnvironment.StartServerAsync();
  28. var client = await testEnvironment.ConnectClientAsync();
  29. await client.SubscribeAsync("#");
  30. var replyReceived = false;
  31. client.UseApplicationMessageReceivedHandler(c =>
  32. {
  33. if (c.ApplicationMessage.Topic == "request")
  34. {
  35. #pragma warning disable 4014
  36. Task.Run(() => client.PublishAsync("reply", null, MqttQualityOfServiceLevel.AtLeastOnce));
  37. #pragma warning restore 4014
  38. }
  39. else
  40. {
  41. replyReceived = true;
  42. }
  43. });
  44. await client.PublishAsync("request", null, MqttQualityOfServiceLevel.AtLeastOnce);
  45. SpinWait.SpinUntil(() => replyReceived, TimeSpan.FromSeconds(10));
  46. Assert.IsTrue(replyReceived);
  47. }
  48. }
  49. [TestMethod]
  50. public async Task Send_Reply_In_Message_Handler()
  51. {
  52. using (var testEnvironment = new TestEnvironment())
  53. {
  54. await testEnvironment.StartServerAsync();
  55. var client1 = await testEnvironment.ConnectClientAsync();
  56. var client2 = await testEnvironment.ConnectClientAsync();
  57. await client1.SubscribeAsync("#");
  58. await client2.SubscribeAsync("#");
  59. var replyReceived = false;
  60. client1.UseApplicationMessageReceivedHandler(async c =>
  61. {
  62. if (c.ApplicationMessage.Topic == "reply")
  63. {
  64. replyReceived = true;
  65. }
  66. });
  67. client2.UseApplicationMessageReceivedHandler(async c =>{ await client2.PublishAsync("reply", null, MqttQualityOfServiceLevel.AtLeastOnce); });
  68. await client1.PublishAsync("request", null, MqttQualityOfServiceLevel.AtLeastOnce);
  69. SpinWait.SpinUntil(() => replyReceived, TimeSpan.FromSeconds(10));
  70. Assert.IsTrue(replyReceived);
  71. }
  72. }
  73. [TestMethod]
  74. public async Task Reconnect()
  75. {
  76. using (var testEnvironment = new TestEnvironment())
  77. {
  78. var server = await testEnvironment.StartServerAsync();
  79. var client = await testEnvironment.ConnectClientAsync();
  80. await Task.Delay(500);
  81. Assert.IsTrue(client.IsConnected);
  82. await server.StopAsync();
  83. await Task.Delay(500);
  84. Assert.IsFalse(client.IsConnected);
  85. await server.StartAsync(new MqttServerOptionsBuilder().WithDefaultEndpointPort(testEnvironment.ServerPort).Build());
  86. await Task.Delay(500);
  87. await client.ConnectAsync(new MqttClientOptionsBuilder().WithTcpServer("127.0.0.1", testEnvironment.ServerPort).Build());
  88. Assert.IsTrue(client.IsConnected);
  89. }
  90. }
  91. [TestMethod]
  92. public async Task PacketIdentifier_In_Publish_Result()
  93. {
  94. using (var testEnvironment = new TestEnvironment())
  95. {
  96. await testEnvironment.StartServerAsync();
  97. var client = await testEnvironment.ConnectClientAsync();
  98. var result = await client.PublishAsync("a", "a", MqttQualityOfServiceLevel.AtMostOnce);
  99. Assert.AreEqual(null, result.PacketIdentifier);
  100. result = await client.PublishAsync("b", "b", MqttQualityOfServiceLevel.AtMostOnce);
  101. Assert.AreEqual(null, result.PacketIdentifier);
  102. result = await client.PublishAsync("a", "a", MqttQualityOfServiceLevel.AtLeastOnce);
  103. Assert.AreEqual((ushort)1, result.PacketIdentifier);
  104. result = await client.PublishAsync("b", "b", MqttQualityOfServiceLevel.AtLeastOnce);
  105. Assert.AreEqual((ushort)2, result.PacketIdentifier);
  106. result = await client.PublishAsync("a", "a", MqttQualityOfServiceLevel.ExactlyOnce);
  107. Assert.AreEqual((ushort)3, result.PacketIdentifier);
  108. result = await client.PublishAsync("b", "b", MqttQualityOfServiceLevel.ExactlyOnce);
  109. Assert.AreEqual((ushort)4, result.PacketIdentifier);
  110. }
  111. }
  112. [TestMethod]
  113. public async Task Invalid_Connect_Throws_Exception()
  114. {
  115. var factory = new MqttFactory();
  116. using (var client = factory.CreateMqttClient())
  117. {
  118. try
  119. {
  120. await client.ConnectAsync(new MqttClientOptionsBuilder().WithTcpServer("wrong-server").Build());
  121. Assert.Fail("Must fail!");
  122. }
  123. catch (Exception exception)
  124. {
  125. Assert.IsNotNull(exception);
  126. Assert.IsInstanceOfType(exception, typeof(MqttCommunicationException));
  127. Assert.IsInstanceOfType(exception.InnerException, typeof(SocketException));
  128. }
  129. }
  130. }
  131. [TestMethod]
  132. public async Task Disconnect_Event_Contains_Exception()
  133. {
  134. var factory = new MqttFactory();
  135. using (var client = factory.CreateMqttClient())
  136. {
  137. Exception ex = null;
  138. client.DisconnectedHandler = new MqttClientDisconnectedHandlerDelegate(e =>
  139. {
  140. ex = e.Exception;
  141. });
  142. try
  143. {
  144. await client.ConnectAsync(new MqttClientOptionsBuilder().WithTcpServer("wrong-server").Build());
  145. }
  146. catch
  147. {
  148. }
  149. await Task.Delay(500);
  150. Assert.IsNotNull(ex);
  151. Assert.IsInstanceOfType(ex, typeof(MqttCommunicationException));
  152. Assert.IsInstanceOfType(ex.InnerException, typeof(SocketException));
  153. }
  154. }
  155. [TestMethod]
  156. public async Task Preserve_Message_Order()
  157. {
  158. // The messages are sent in reverse or to ensure that the delay in the handler
  159. // needs longer for the first messages and later messages may be processed earlier (if there
  160. // is an issue).
  161. const int MessagesCount = 50;
  162. using (var testEnvironment = new TestEnvironment())
  163. {
  164. await testEnvironment.StartServerAsync();
  165. var client1 = await testEnvironment.ConnectClientAsync();
  166. await client1.SubscribeAsync("x");
  167. var receivedValues = new List<int>();
  168. async Task Handler1(MqttApplicationMessageReceivedEventArgs eventArgs)
  169. {
  170. var value = int.Parse(eventArgs.ApplicationMessage.ConvertPayloadToString());
  171. await Task.Delay(value);
  172. lock (receivedValues)
  173. {
  174. receivedValues.Add(value);
  175. }
  176. }
  177. client1.UseApplicationMessageReceivedHandler(Handler1);
  178. var client2 = await testEnvironment.ConnectClientAsync();
  179. for (var i = MessagesCount; i > 0; i--)
  180. {
  181. await client2.PublishAsync("x", i.ToString());
  182. }
  183. await Task.Delay(5000);
  184. for (var i = MessagesCount; i > 0; i--)
  185. {
  186. Assert.AreEqual(i, receivedValues[MessagesCount - i]);
  187. }
  188. }
  189. }
  190. [TestMethod]
  191. public async Task Send_Reply_For_Any_Received_Message()
  192. {
  193. using (var testEnvironment = new TestEnvironment())
  194. {
  195. await testEnvironment.StartServerAsync();
  196. var client1 = await testEnvironment.ConnectClientAsync();
  197. await client1.SubscribeAsync("request/+");
  198. async Task Handler1(MqttApplicationMessageReceivedEventArgs eventArgs)
  199. {
  200. await client1.PublishAsync($"reply/{eventArgs.ApplicationMessage.Topic}");
  201. }
  202. client1.UseApplicationMessageReceivedHandler(Handler1);
  203. var client2 = await testEnvironment.ConnectClientAsync();
  204. await client2.SubscribeAsync("reply/#");
  205. var replies = new List<string>();
  206. void Handler2(MqttApplicationMessageReceivedEventArgs eventArgs)
  207. {
  208. lock (replies)
  209. {
  210. replies.Add(eventArgs.ApplicationMessage.Topic);
  211. }
  212. }
  213. client2.UseApplicationMessageReceivedHandler((Action<MqttApplicationMessageReceivedEventArgs>)Handler2);
  214. await Task.Delay(500);
  215. await client2.PublishAsync("request/a");
  216. await client2.PublishAsync("request/b");
  217. await client2.PublishAsync("request/c");
  218. await Task.Delay(500);
  219. Assert.AreEqual("reply/request/a,reply/request/b,reply/request/c", string.Join(",", replies));
  220. }
  221. }
  222. [TestMethod]
  223. public async Task Publish_With_Correct_Retain_Flag()
  224. {
  225. using (var testEnvironment = new TestEnvironment())
  226. {
  227. await testEnvironment.StartServerAsync();
  228. var receivedMessages = new List<MqttApplicationMessage>();
  229. var client1 = await testEnvironment.ConnectClientAsync();
  230. client1.UseApplicationMessageReceivedHandler(c =>
  231. {
  232. lock (receivedMessages)
  233. {
  234. receivedMessages.Add(c.ApplicationMessage);
  235. }
  236. });
  237. await client1.SubscribeAsync("a");
  238. var client2 = await testEnvironment.ConnectClientAsync();
  239. var message = new MqttApplicationMessageBuilder().WithTopic("a").WithRetainFlag().Build();
  240. await client2.PublishAsync(message);
  241. await Task.Delay(500);
  242. Assert.AreEqual(1, receivedMessages.Count);
  243. Assert.IsFalse(receivedMessages.First().Retain); // Must be false even if set above!
  244. }
  245. }
  246. [TestMethod]
  247. public async Task Subscribe_In_Callback_Events()
  248. {
  249. using (var testEnvironment = new TestEnvironment())
  250. {
  251. await testEnvironment.StartServerAsync();
  252. var receivedMessages = new List<MqttApplicationMessage>();
  253. var client = testEnvironment.CreateClient();
  254. client.ConnectedHandler = new MqttClientConnectedHandlerDelegate(async e =>
  255. {
  256. await client.SubscribeAsync("RCU/P1/H0001/R0003");
  257. var msg = new MqttApplicationMessageBuilder()
  258. .WithPayload("DA|18RS00SC00XI0000RV00R100R200R300R400L100L200L300L400Y100Y200AC0102031800BELK0000BM0000|")
  259. .WithTopic("RCU/P1/H0001/R0003");
  260. await client.PublishAsync(msg.Build());
  261. });
  262. client.UseApplicationMessageReceivedHandler(c =>
  263. {
  264. lock (receivedMessages)
  265. {
  266. receivedMessages.Add(c.ApplicationMessage);
  267. }
  268. });
  269. await client.ConnectAsync(new MqttClientOptionsBuilder().WithTcpServer("localhost", testEnvironment.ServerPort).Build());
  270. await Task.Delay(500);
  271. Assert.AreEqual(1, receivedMessages.Count);
  272. Assert.AreEqual("DA|18RS00SC00XI0000RV00R100R200R300R400L100L200L300L400Y100Y200AC0102031800BELK0000BM0000|", receivedMessages.First().ConvertPayloadToString());
  273. }
  274. }
  275. [TestMethod]
  276. public async Task Message_Send_Retry()
  277. {
  278. using (var testEnvironment = new TestEnvironment())
  279. {
  280. testEnvironment.IgnoreClientLogErrors = true;
  281. testEnvironment.IgnoreServerLogErrors = true;
  282. await testEnvironment.StartServerAsync(
  283. new MqttServerOptionsBuilder()
  284. .WithPersistentSessions()
  285. .WithDefaultCommunicationTimeout(TimeSpan.FromMilliseconds(250)));
  286. var client1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithCleanSession(false));
  287. await client1.SubscribeAsync("x", MqttQualityOfServiceLevel.AtLeastOnce);
  288. var retries = 0;
  289. async Task Handler1(MqttApplicationMessageReceivedEventArgs eventArgs)
  290. {
  291. retries++;
  292. await Task.Delay(1000);
  293. throw new Exception("Broken!");
  294. }
  295. client1.UseApplicationMessageReceivedHandler(Handler1);
  296. var client2 = await testEnvironment.ConnectClientAsync();
  297. await client2.PublishAsync("x");
  298. await Task.Delay(3000);
  299. // The server should disconnect clients which are not responding.
  300. Assert.IsFalse(client1.IsConnected);
  301. await client1.ReconnectAsync().ConfigureAwait(false);
  302. await Task.Delay(1000);
  303. Assert.AreEqual(2, retries);
  304. }
  305. }
  306. [TestMethod]
  307. public async Task NoConnectedHandler_Connect_DoesNotThrowException()
  308. {
  309. using (var testEnvironment = new TestEnvironment())
  310. {
  311. await testEnvironment.StartServerAsync();
  312. var client = await testEnvironment.ConnectClientAsync();
  313. Assert.IsTrue(client.IsConnected);
  314. }
  315. }
  316. [TestMethod]
  317. public async Task NoDisconnectedHandler_Disconnect_DoesNotThrowException()
  318. {
  319. using (var testEnvironment = new TestEnvironment())
  320. {
  321. await testEnvironment.StartServerAsync();
  322. var client = await testEnvironment.ConnectClientAsync();
  323. Assert.IsTrue(client.IsConnected);
  324. await client.DisconnectAsync();
  325. Assert.IsFalse(client.IsConnected);
  326. }
  327. }
  328. [TestMethod]
  329. public async Task Frequent_Connects()
  330. {
  331. using (var testEnvironment = new TestEnvironment())
  332. {
  333. await testEnvironment.StartServerAsync();
  334. var clients = new List<IMqttClient>();
  335. for (var i = 0; i < 100; i++)
  336. {
  337. clients.Add(await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("a")));
  338. }
  339. var clientStatus = await testEnvironment.Server.GetClientStatusAsync();
  340. var sessionStatus = await testEnvironment.Server.GetSessionStatusAsync();
  341. for (var i = 0; i < 98; i++)
  342. {
  343. Assert.IsFalse(clients[i].IsConnected);
  344. }
  345. Assert.IsTrue(clients[99].IsConnected);
  346. Assert.AreEqual(1, clientStatus.Count);
  347. Assert.AreEqual(1, sessionStatus.Count);
  348. var receiveClient = clients[99];
  349. object receivedPayload = null;
  350. receiveClient.UseApplicationMessageReceivedHandler(e =>
  351. {
  352. receivedPayload = e.ApplicationMessage.ConvertPayloadToString();
  353. });
  354. await receiveClient.SubscribeAsync("x");
  355. var sendClient = await testEnvironment.ConnectClientAsync();
  356. await sendClient.PublishAsync("x", "1");
  357. await Task.Delay(100);
  358. Assert.AreEqual("1", receivedPayload);
  359. }
  360. }
  361. [TestMethod]
  362. public async Task No_Payload()
  363. {
  364. using (var testEnvironment = new TestEnvironment())
  365. {
  366. await testEnvironment.StartServerAsync();
  367. var sender = await testEnvironment.ConnectClientAsync();
  368. var receiver = await testEnvironment.ConnectClientAsync();
  369. var message = new MqttApplicationMessageBuilder()
  370. .WithTopic("A");
  371. await receiver.SubscribeAsync(new MqttClientSubscribeOptions
  372. {
  373. TopicFilters = new List<TopicFilter> { new TopicFilter { Topic = "#" } }
  374. }, CancellationToken.None);
  375. MqttApplicationMessage receivedMessage = null;
  376. receiver.UseApplicationMessageReceivedHandler(e => receivedMessage = e.ApplicationMessage);
  377. await sender.PublishAsync(message.Build(), CancellationToken.None);
  378. await Task.Delay(1000);
  379. Assert.IsNotNull(receivedMessage);
  380. Assert.AreEqual("A", receivedMessage.Topic);
  381. Assert.AreEqual(null, receivedMessage.Payload);
  382. }
  383. }
  384. }
  385. }