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.
 
 
 
 

405 lines
14 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 PacketIdentifier_In_Publish_Result()
  24. {
  25. using (var testEnvironment = new TestEnvironment())
  26. {
  27. await testEnvironment.StartServerAsync();
  28. var client = await testEnvironment.ConnectClientAsync();
  29. var result = await client.PublishAsync("a", "a", MqttQualityOfServiceLevel.AtMostOnce);
  30. Assert.AreEqual(null, result.PacketIdentifier);
  31. result = await client.PublishAsync("b", "b", MqttQualityOfServiceLevel.AtMostOnce);
  32. Assert.AreEqual(null, result.PacketIdentifier);
  33. result = await client.PublishAsync("a", "a", MqttQualityOfServiceLevel.AtLeastOnce);
  34. Assert.AreEqual((ushort)1, result.PacketIdentifier);
  35. result = await client.PublishAsync("b", "b", MqttQualityOfServiceLevel.AtLeastOnce);
  36. Assert.AreEqual((ushort)2, result.PacketIdentifier);
  37. result = await client.PublishAsync("a", "a", MqttQualityOfServiceLevel.ExactlyOnce);
  38. Assert.AreEqual((ushort)3, result.PacketIdentifier);
  39. result = await client.PublishAsync("b", "b", MqttQualityOfServiceLevel.ExactlyOnce);
  40. Assert.AreEqual((ushort)4, result.PacketIdentifier);
  41. }
  42. }
  43. [TestMethod]
  44. public async Task Invalid_Connect_Throws_Exception()
  45. {
  46. var factory = new MqttFactory();
  47. using (var client = factory.CreateMqttClient())
  48. {
  49. try
  50. {
  51. await client.ConnectAsync(new MqttClientOptionsBuilder().WithTcpServer("wrong-server").Build());
  52. Assert.Fail("Must fail!");
  53. }
  54. catch (Exception exception)
  55. {
  56. Assert.IsNotNull(exception);
  57. Assert.IsInstanceOfType(exception, typeof(MqttCommunicationException));
  58. Assert.IsInstanceOfType(exception.InnerException, typeof(SocketException));
  59. }
  60. }
  61. }
  62. [TestMethod]
  63. public async Task Disconnect_Event_Contains_Exception()
  64. {
  65. var factory = new MqttFactory();
  66. using (var client = factory.CreateMqttClient())
  67. {
  68. Exception ex = null;
  69. client.DisconnectedHandler = new MqttClientDisconnectedHandlerDelegate(e =>
  70. {
  71. ex = e.Exception;
  72. });
  73. try
  74. {
  75. await client.ConnectAsync(new MqttClientOptionsBuilder().WithTcpServer("wrong-server").Build());
  76. }
  77. catch
  78. {
  79. }
  80. Assert.IsNotNull(ex);
  81. Assert.IsInstanceOfType(ex, typeof(MqttCommunicationException));
  82. Assert.IsInstanceOfType(ex.InnerException, typeof(SocketException));
  83. }
  84. }
  85. [TestMethod]
  86. public async Task Preserve_Message_Order()
  87. {
  88. // The messages are sent in reverse or to ensure that the delay in the handler
  89. // needs longer for the first messages and later messages may be processed earlier (if there
  90. // is an issue).
  91. const int MessagesCount = 50;
  92. using (var testEnvironment = new TestEnvironment())
  93. {
  94. await testEnvironment.StartServerAsync();
  95. var client1 = await testEnvironment.ConnectClientAsync();
  96. await client1.SubscribeAsync("x");
  97. var receivedValues = new List<int>();
  98. async Task Handler1(MqttApplicationMessageReceivedEventArgs eventArgs)
  99. {
  100. var value = int.Parse(eventArgs.ApplicationMessage.ConvertPayloadToString());
  101. await Task.Delay(value);
  102. lock (receivedValues)
  103. {
  104. receivedValues.Add(value);
  105. }
  106. }
  107. client1.UseApplicationMessageReceivedHandler(Handler1);
  108. var client2 = await testEnvironment.ConnectClientAsync();
  109. for (var i = MessagesCount; i > 0; i--)
  110. {
  111. await client2.PublishAsync("x", i.ToString());
  112. }
  113. await Task.Delay(5000);
  114. for (var i = MessagesCount; i > 0; i--)
  115. {
  116. Assert.AreEqual(i, receivedValues[MessagesCount - i]);
  117. }
  118. }
  119. }
  120. [TestMethod]
  121. public async Task Send_Reply_For_Any_Received_Message()
  122. {
  123. using (var testEnvironment = new TestEnvironment())
  124. {
  125. await testEnvironment.StartServerAsync();
  126. var client1 = await testEnvironment.ConnectClientAsync();
  127. await client1.SubscribeAsync("request/+");
  128. async Task Handler1(MqttApplicationMessageReceivedEventArgs eventArgs)
  129. {
  130. await client1.PublishAsync($"reply/{eventArgs.ApplicationMessage.Topic}");
  131. }
  132. client1.UseApplicationMessageReceivedHandler(Handler1);
  133. var client2 = await testEnvironment.ConnectClientAsync();
  134. await client2.SubscribeAsync("reply/#");
  135. var replies = new List<string>();
  136. void Handler2(MqttApplicationMessageReceivedEventArgs eventArgs)
  137. {
  138. lock (replies)
  139. {
  140. replies.Add(eventArgs.ApplicationMessage.Topic);
  141. }
  142. }
  143. client2.UseApplicationMessageReceivedHandler((Action<MqttApplicationMessageReceivedEventArgs>)Handler2);
  144. await Task.Delay(500);
  145. await client2.PublishAsync("request/a");
  146. await client2.PublishAsync("request/b");
  147. await client2.PublishAsync("request/c");
  148. await Task.Delay(500);
  149. Assert.AreEqual("reply/request/a,reply/request/b,reply/request/c", string.Join(",", replies));
  150. }
  151. }
  152. [TestMethod]
  153. public async Task Publish_With_Correct_Retain_Flag()
  154. {
  155. using (var testEnvironment = new TestEnvironment())
  156. {
  157. await testEnvironment.StartServerAsync();
  158. var receivedMessages = new List<MqttApplicationMessage>();
  159. var client1 = await testEnvironment.ConnectClientAsync();
  160. client1.UseApplicationMessageReceivedHandler(c =>
  161. {
  162. lock (receivedMessages)
  163. {
  164. receivedMessages.Add(c.ApplicationMessage);
  165. }
  166. });
  167. await client1.SubscribeAsync("a");
  168. var client2 = await testEnvironment.ConnectClientAsync();
  169. var message = new MqttApplicationMessageBuilder().WithTopic("a").WithRetainFlag().Build();
  170. await client2.PublishAsync(message);
  171. await Task.Delay(500);
  172. Assert.AreEqual(1, receivedMessages.Count);
  173. Assert.IsFalse(receivedMessages.First().Retain); // Must be false even if set above!
  174. }
  175. }
  176. [TestMethod]
  177. public async Task Subscribe_In_Callback_Events()
  178. {
  179. using (var testEnvironment = new TestEnvironment())
  180. {
  181. await testEnvironment.StartServerAsync();
  182. var receivedMessages = new List<MqttApplicationMessage>();
  183. var client = testEnvironment.CreateClient();
  184. client.ConnectedHandler = new MqttClientConnectedHandlerDelegate(async e =>
  185. {
  186. await client.SubscribeAsync("RCU/P1/H0001/R0003");
  187. var msg = new MqttApplicationMessageBuilder()
  188. .WithPayload("DA|18RS00SC00XI0000RV00R100R200R300R400L100L200L300L400Y100Y200AC0102031800BELK0000BM0000|")
  189. .WithTopic("RCU/P1/H0001/R0003");
  190. await client.PublishAsync(msg.Build());
  191. });
  192. client.UseApplicationMessageReceivedHandler(c =>
  193. {
  194. lock (receivedMessages)
  195. {
  196. receivedMessages.Add(c.ApplicationMessage);
  197. }
  198. });
  199. await client.ConnectAsync(new MqttClientOptionsBuilder().WithTcpServer("localhost", testEnvironment.ServerPort).Build());
  200. await Task.Delay(500);
  201. Assert.AreEqual(1, receivedMessages.Count);
  202. Assert.AreEqual("DA|18RS00SC00XI0000RV00R100R200R300R400L100L200L300L400Y100Y200AC0102031800BELK0000BM0000|", receivedMessages.First().ConvertPayloadToString());
  203. }
  204. }
  205. [TestMethod]
  206. public async Task Message_Send_Retry()
  207. {
  208. using (var testEnvironment = new TestEnvironment())
  209. {
  210. testEnvironment.IgnoreClientLogErrors = true;
  211. testEnvironment.IgnoreServerLogErrors = true;
  212. await testEnvironment.StartServerAsync(
  213. new MqttServerOptionsBuilder()
  214. .WithPersistentSessions()
  215. .WithDefaultCommunicationTimeout(TimeSpan.FromMilliseconds(250)));
  216. var client1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithCleanSession(false));
  217. await client1.SubscribeAsync("x", MqttQualityOfServiceLevel.AtLeastOnce);
  218. var retries = 0;
  219. async Task Handler1(MqttApplicationMessageReceivedEventArgs eventArgs)
  220. {
  221. retries++;
  222. await Task.Delay(1000);
  223. throw new Exception("Broken!");
  224. }
  225. client1.UseApplicationMessageReceivedHandler(Handler1);
  226. var client2 = await testEnvironment.ConnectClientAsync();
  227. await client2.PublishAsync("x");
  228. await Task.Delay(3000);
  229. // The server should disconnect clients which are not responding.
  230. Assert.IsFalse(client1.IsConnected);
  231. await client1.ReconnectAsync().ConfigureAwait(false);
  232. await Task.Delay(1000);
  233. Assert.AreEqual(2, retries);
  234. }
  235. }
  236. [TestMethod]
  237. public async Task NoConnectedHandler_Connect_DoesNotThrowException()
  238. {
  239. using (var testEnvironment = new TestEnvironment())
  240. {
  241. await testEnvironment.StartServerAsync();
  242. var client = await testEnvironment.ConnectClientAsync();
  243. Assert.IsTrue(client.IsConnected);
  244. }
  245. }
  246. [TestMethod]
  247. public async Task NoDisconnectedHandler_Disconnect_DoesNotThrowException()
  248. {
  249. using (var testEnvironment = new TestEnvironment())
  250. {
  251. await testEnvironment.StartServerAsync();
  252. var client = await testEnvironment.ConnectClientAsync();
  253. Assert.IsTrue(client.IsConnected);
  254. await client.DisconnectAsync();
  255. Assert.IsFalse(client.IsConnected);
  256. }
  257. }
  258. [TestMethod]
  259. public async Task Frequent_Connects()
  260. {
  261. using (var testEnvironment = new TestEnvironment())
  262. {
  263. await testEnvironment.StartServerAsync();
  264. var clients = new List<IMqttClient>();
  265. for (var i = 0; i < 100; i++)
  266. {
  267. clients.Add(await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("a")));
  268. }
  269. var clientStatus = await testEnvironment.Server.GetClientStatusAsync();
  270. var sessionStatus = await testEnvironment.Server.GetSessionStatusAsync();
  271. for (var i = 0; i < 98; i++)
  272. {
  273. Assert.IsFalse(clients[i].IsConnected);
  274. }
  275. Assert.IsTrue(clients[99].IsConnected);
  276. Assert.AreEqual(1, clientStatus.Count);
  277. Assert.AreEqual(1, sessionStatus.Count);
  278. var receiveClient = clients[99];
  279. object receivedPayload = null;
  280. receiveClient.UseApplicationMessageReceivedHandler(e =>
  281. {
  282. receivedPayload = e.ApplicationMessage.ConvertPayloadToString();
  283. });
  284. await receiveClient.SubscribeAsync("x");
  285. var sendClient = await testEnvironment.ConnectClientAsync();
  286. await sendClient.PublishAsync("x", "1");
  287. await Task.Delay(100);
  288. Assert.AreEqual("1", receivedPayload);
  289. }
  290. }
  291. [TestMethod]
  292. public async Task No_Payload()
  293. {
  294. using (var testEnvironment = new TestEnvironment())
  295. {
  296. await testEnvironment.StartServerAsync();
  297. var sender = await testEnvironment.ConnectClientAsync();
  298. var receiver = await testEnvironment.ConnectClientAsync();
  299. var message = new MqttApplicationMessageBuilder()
  300. .WithTopic("A");
  301. await receiver.SubscribeAsync(new MqttClientSubscribeOptions
  302. {
  303. TopicFilters = new List<TopicFilter> { new TopicFilter { Topic = "#" } }
  304. }, CancellationToken.None);
  305. MqttApplicationMessage receivedMessage = null;
  306. receiver.UseApplicationMessageReceivedHandler(e => receivedMessage = e.ApplicationMessage);
  307. await sender.PublishAsync(message.Build(), CancellationToken.None);
  308. await Task.Delay(1000);
  309. Assert.IsNotNull(receivedMessage);
  310. Assert.AreEqual("A", receivedMessage.Topic);
  311. Assert.AreEqual(null, receivedMessage.Payload);
  312. }
  313. }
  314. }
  315. }