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.
 
 
 
 

970 lines
35 KiB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Net.Sockets;
  5. using System.Text;
  6. using System.Threading;
  7. using System.Threading.Tasks;
  8. using Microsoft.VisualStudio.TestTools.UnitTesting;
  9. using MQTTnet.Adapter;
  10. using MQTTnet.Client;
  11. using MQTTnet.Client.Connecting;
  12. using MQTTnet.Client.Disconnecting;
  13. using MQTTnet.Client.Options;
  14. using MQTTnet.Client.Receiving;
  15. using MQTTnet.Protocol;
  16. using MQTTnet.Server;
  17. using MQTTnet.Tests.Mockups;
  18. namespace MQTTnet.Tests
  19. {
  20. [TestClass]
  21. public class Server_Tests
  22. {
  23. [TestMethod]
  24. public async Task Publish_At_Most_Once_0x00()
  25. {
  26. await TestPublishAsync(
  27. "A/B/C",
  28. MqttQualityOfServiceLevel.AtMostOnce,
  29. "A/B/C",
  30. MqttQualityOfServiceLevel.AtMostOnce,
  31. 1);
  32. }
  33. [TestMethod]
  34. public async Task Publish_At_Least_Once_0x01()
  35. {
  36. await TestPublishAsync(
  37. "A/B/C",
  38. MqttQualityOfServiceLevel.AtLeastOnce,
  39. "A/B/C",
  40. MqttQualityOfServiceLevel.AtLeastOnce,
  41. 1);
  42. }
  43. [TestMethod]
  44. public async Task Publish_Exactly_Once_0x02()
  45. {
  46. await TestPublishAsync(
  47. "A/B/C",
  48. MqttQualityOfServiceLevel.ExactlyOnce,
  49. "A/B/C",
  50. MqttQualityOfServiceLevel.ExactlyOnce,
  51. 1);
  52. }
  53. [TestMethod]
  54. public async Task Will_Message_Do_Not_Send()
  55. {
  56. using (var testEnvironment = new TestEnvironment())
  57. {
  58. var receivedMessagesCount = 0;
  59. await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder());
  60. var willMessage = new MqttApplicationMessageBuilder().WithTopic("My/last/will").WithAtMostOnceQoS().Build();
  61. var clientOptions = new MqttClientOptionsBuilder().WithWillMessage(willMessage);
  62. var c1 = await testEnvironment.ConnectClientAsync();
  63. c1.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate(c => Interlocked.Increment(ref receivedMessagesCount));
  64. await c1.SubscribeAsync(new TopicFilterBuilder().WithTopic("#").Build());
  65. var c2 = await testEnvironment.ConnectClientAsync(clientOptions);
  66. await c2.DisconnectAsync().ConfigureAwait(false);
  67. await Task.Delay(1000);
  68. Assert.AreEqual(0, receivedMessagesCount);
  69. }
  70. }
  71. [TestMethod]
  72. public async Task Will_Message_Send()
  73. {
  74. using (var testEnvironment = new TestEnvironment())
  75. {
  76. var receivedMessagesCount = 0;
  77. await testEnvironment.StartServerAsync();
  78. var willMessage = new MqttApplicationMessageBuilder().WithTopic("My/last/will").WithAtMostOnceQoS().Build();
  79. var clientOptions = new MqttClientOptionsBuilder().WithWillMessage(willMessage);
  80. var c1 = await testEnvironment.ConnectClientAsync();
  81. c1.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
  82. await c1.SubscribeAsync(new TopicFilterBuilder().WithTopic("#").Build());
  83. var c2 = await testEnvironment.ConnectClientAsync(clientOptions);
  84. c2.Dispose(); // Dispose will not send a DISCONNECT pattern first so the will message must be sent.
  85. await Task.Delay(1000);
  86. Assert.AreEqual(1, receivedMessagesCount);
  87. }
  88. }
  89. [TestMethod]
  90. public async Task Subscribe_Unsubscribe()
  91. {
  92. using (var testEnvironment = new TestEnvironment())
  93. {
  94. var receivedMessagesCount = 0;
  95. var server = await testEnvironment.StartServerAsync();
  96. var c1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("c1"));
  97. c1.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
  98. var c2 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("c2"));
  99. var message = new MqttApplicationMessageBuilder().WithTopic("a").WithAtLeastOnceQoS().Build();
  100. await c2.PublishAsync(message);
  101. await Task.Delay(500);
  102. Assert.AreEqual(0, receivedMessagesCount);
  103. var subscribeEventCalled = false;
  104. server.ClientSubscribedTopicHandler = new MqttServerClientSubscribedHandlerDelegate(e =>
  105. {
  106. subscribeEventCalled = e.TopicFilter.Topic == "a" && e.ClientId == "c1";
  107. });
  108. await c1.SubscribeAsync(new TopicFilter { Topic = "a", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce });
  109. await Task.Delay(250);
  110. Assert.IsTrue(subscribeEventCalled, "Subscribe event not called.");
  111. await c2.PublishAsync(message);
  112. await Task.Delay(250);
  113. Assert.AreEqual(1, receivedMessagesCount);
  114. var unsubscribeEventCalled = false;
  115. server.ClientUnsubscribedTopicHandler = new MqttServerClientUnsubscribedTopicHandlerDelegate(e =>
  116. {
  117. unsubscribeEventCalled = e.TopicFilter == "a" && e.ClientId == "c1";
  118. });
  119. await c1.UnsubscribeAsync("a");
  120. await Task.Delay(250);
  121. Assert.IsTrue(unsubscribeEventCalled, "Unsubscribe event not called.");
  122. await c2.PublishAsync(message);
  123. await Task.Delay(500);
  124. Assert.AreEqual(1, receivedMessagesCount);
  125. await Task.Delay(500);
  126. Assert.AreEqual(1, receivedMessagesCount);
  127. }
  128. }
  129. [TestMethod]
  130. public async Task Publish_From_Server()
  131. {
  132. using (var testEnvironment = new TestEnvironment())
  133. {
  134. var server = await testEnvironment.StartServerAsync();
  135. var receivedMessagesCount = 0;
  136. var client = await testEnvironment.ConnectClientAsync();
  137. client.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
  138. var message = new MqttApplicationMessageBuilder().WithTopic("a").WithAtLeastOnceQoS().Build();
  139. await client.SubscribeAsync(new TopicFilter { Topic = "a", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce });
  140. await server.PublishAsync(message);
  141. await Task.Delay(1000);
  142. Assert.AreEqual(1, receivedMessagesCount);
  143. }
  144. }
  145. [TestMethod]
  146. public async Task Publish_Multiple_Clients()
  147. {
  148. var receivedMessagesCount = 0;
  149. var locked = new object();
  150. using (var testEnvironment = new TestEnvironment())
  151. {
  152. await testEnvironment.StartServerAsync();
  153. var c1 = await testEnvironment.ConnectClientAsync();
  154. var c2 = await testEnvironment.ConnectClientAsync();
  155. c1.UseApplicationMessageReceivedHandler(c =>
  156. {
  157. lock (locked)
  158. {
  159. receivedMessagesCount++;
  160. }
  161. });
  162. c2.UseApplicationMessageReceivedHandler(c =>
  163. {
  164. lock (locked)
  165. {
  166. receivedMessagesCount++;
  167. }
  168. });
  169. await c1.SubscribeAsync(new TopicFilter { Topic = "a", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce });
  170. await c2.SubscribeAsync(new TopicFilter { Topic = "a", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce });
  171. var message = new MqttApplicationMessageBuilder().WithTopic("a").WithAtLeastOnceQoS().Build();
  172. for (var i = 0; i < 1000; i++)
  173. {
  174. await c1.PublishAsync(message);
  175. }
  176. await Task.Delay(500);
  177. Assert.AreEqual(2000, receivedMessagesCount);
  178. }
  179. }
  180. [TestMethod]
  181. public async Task Session_Takeover()
  182. {
  183. using (var testEnvironment = new TestEnvironment())
  184. {
  185. await testEnvironment.StartServerAsync();
  186. var options = new MqttClientOptionsBuilder()
  187. .WithCleanSession(false)
  188. .WithClientId("a");
  189. var client1 = await testEnvironment.ConnectClientAsync(options);
  190. await Task.Delay(500);
  191. var client2 = await testEnvironment.ConnectClientAsync(options);
  192. await Task.Delay(500);
  193. Assert.IsFalse(client1.IsConnected);
  194. Assert.IsTrue(client2.IsConnected);
  195. }
  196. }
  197. [TestMethod]
  198. public async Task No_Messages_If_No_Subscription()
  199. {
  200. using (var testEnvironment = new TestEnvironment())
  201. {
  202. await testEnvironment.StartServerAsync();
  203. var client = await testEnvironment.ConnectClientAsync();
  204. var receivedMessages = new List<MqttApplicationMessage>();
  205. client.ConnectedHandler = new MqttClientConnectedHandlerDelegate(async e =>
  206. {
  207. await client.PublishAsync("Connected");
  208. });
  209. client.UseApplicationMessageReceivedHandler(c =>
  210. {
  211. lock (receivedMessages)
  212. {
  213. receivedMessages.Add(c.ApplicationMessage);
  214. }
  215. });
  216. await Task.Delay(500);
  217. await client.PublishAsync("Hello");
  218. await Task.Delay(500);
  219. Assert.AreEqual(0, receivedMessages.Count);
  220. }
  221. }
  222. [TestMethod]
  223. public async Task Set_Subscription_At_Server()
  224. {
  225. using (var testEnvironment = new TestEnvironment())
  226. {
  227. var server = await testEnvironment.StartServerAsync();
  228. server.ClientConnectedHandler = new MqttServerClientConnectedHandlerDelegate(e => server.SubscribeAsync(e.ClientId, "topic1"));
  229. var client = await testEnvironment.ConnectClientAsync();
  230. var receivedMessages = new List<MqttApplicationMessage>();
  231. client.UseApplicationMessageReceivedHandler(c =>
  232. {
  233. lock (receivedMessages)
  234. {
  235. receivedMessages.Add(c.ApplicationMessage);
  236. }
  237. });
  238. await Task.Delay(500);
  239. await client.PublishAsync("Hello");
  240. await Task.Delay(100);
  241. Assert.AreEqual(0, receivedMessages.Count);
  242. await client.PublishAsync("topic1");
  243. await Task.Delay(100);
  244. Assert.AreEqual(1, receivedMessages.Count);
  245. }
  246. }
  247. [TestMethod]
  248. public async Task Shutdown_Disconnects_Clients_Gracefully()
  249. {
  250. using (var testEnvironment = new TestEnvironment())
  251. {
  252. var server = await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder());
  253. var disconnectCalled = 0;
  254. var c1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder());
  255. c1.DisconnectedHandler = new MqttClientDisconnectedHandlerDelegate(e => disconnectCalled++);
  256. await Task.Delay(100);
  257. await server.StopAsync();
  258. await Task.Delay(100);
  259. Assert.AreEqual(1, disconnectCalled);
  260. }
  261. }
  262. [TestMethod]
  263. public async Task Handle_Clean_Disconnect()
  264. {
  265. using (var testEnvironment = new TestEnvironment())
  266. {
  267. var server = await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder());
  268. var clientConnectedCalled = 0;
  269. var clientDisconnectedCalled = 0;
  270. server.ClientConnectedHandler = new MqttServerClientConnectedHandlerDelegate(_ => Interlocked.Increment(ref clientConnectedCalled));
  271. server.ClientDisconnectedHandler = new MqttServerClientDisconnectedHandlerDelegate(_ => Interlocked.Increment(ref clientDisconnectedCalled));
  272. var c1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder());
  273. Assert.AreEqual(1, clientConnectedCalled);
  274. Assert.AreEqual(0, clientDisconnectedCalled);
  275. await Task.Delay(500);
  276. await c1.DisconnectAsync();
  277. await Task.Delay(500);
  278. Assert.AreEqual(1, clientConnectedCalled);
  279. Assert.AreEqual(1, clientDisconnectedCalled);
  280. }
  281. }
  282. [TestMethod]
  283. public async Task Client_Disconnect_Without_Errors()
  284. {
  285. using (var testEnvironment = new TestEnvironment())
  286. {
  287. bool clientWasConnected;
  288. var server = await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder());
  289. try
  290. {
  291. var client = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder());
  292. clientWasConnected = true;
  293. await client.DisconnectAsync();
  294. await Task.Delay(500);
  295. }
  296. finally
  297. {
  298. await server.StopAsync();
  299. }
  300. Assert.IsTrue(clientWasConnected);
  301. testEnvironment.ThrowIfLogErrors();
  302. }
  303. }
  304. [TestMethod]
  305. public async Task Handle_Lots_Of_Parallel_Retained_Messages()
  306. {
  307. const int ClientCount = 50;
  308. using (var testEnvironment = new TestEnvironment())
  309. {
  310. var server = await testEnvironment.StartServerAsync();
  311. var tasks = new List<Task>();
  312. for (var i = 0; i < ClientCount; i++)
  313. {
  314. var i2 = i;
  315. var testEnvironment2 = testEnvironment;
  316. tasks.Add(Task.Run(async () =>
  317. {
  318. try
  319. {
  320. using (var client = await testEnvironment2.ConnectClientAsync())
  321. {
  322. // Clear retained message.
  323. await client.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("r" + i2)
  324. .WithPayload(new byte[0]).WithRetainFlag().Build());
  325. // Set retained message.
  326. await client.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("r" + i2)
  327. .WithPayload("value").WithRetainFlag().Build());
  328. await client.DisconnectAsync();
  329. }
  330. }
  331. catch (Exception exception)
  332. {
  333. testEnvironment2.TrackException(exception);
  334. }
  335. }));
  336. }
  337. await Task.WhenAll(tasks);
  338. await Task.Delay(1000);
  339. var retainedMessages = await server.GetRetainedMessagesAsync();
  340. Assert.AreEqual(ClientCount, retainedMessages.Count);
  341. for (var i = 0; i < ClientCount; i++)
  342. {
  343. Assert.IsTrue(retainedMessages.Any(m => m.Topic == "r" + i));
  344. }
  345. }
  346. }
  347. [TestMethod]
  348. public async Task Retained_Messages_Flow()
  349. {
  350. using (var testEnvironment = new TestEnvironment())
  351. {
  352. var retainedMessage = new MqttApplicationMessageBuilder().WithTopic("r").WithPayload("r").WithRetainFlag().Build();
  353. await testEnvironment.StartServerAsync();
  354. var c1 = await testEnvironment.ConnectClientAsync();
  355. var receivedMessages = 0;
  356. var c2 = await testEnvironment.ConnectClientAsync();
  357. c2.UseApplicationMessageReceivedHandler(c =>
  358. {
  359. Interlocked.Increment(ref receivedMessages);
  360. });
  361. await c1.PublishAsync(retainedMessage);
  362. await c1.DisconnectAsync();
  363. await Task.Delay(500);
  364. for (var i = 0; i < 5; i++)
  365. {
  366. await c2.UnsubscribeAsync("r");
  367. await Task.Delay(100);
  368. Assert.AreEqual(i, receivedMessages);
  369. await c2.SubscribeAsync("r");
  370. await Task.Delay(100);
  371. Assert.AreEqual(i + 1, receivedMessages);
  372. }
  373. await c2.DisconnectAsync();
  374. }
  375. }
  376. [TestMethod]
  377. public async Task Receive_No_Retained_Message_After_Subscribe()
  378. {
  379. using (var testEnvironment = new TestEnvironment())
  380. {
  381. await testEnvironment.StartServerAsync();
  382. var c1 = await testEnvironment.ConnectClientAsync();
  383. await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build());
  384. await c1.DisconnectAsync();
  385. var receivedMessagesCount = 0;
  386. var c2 = await testEnvironment.ConnectClientAsync();
  387. c2.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
  388. await c2.SubscribeAsync(new TopicFilterBuilder().WithTopic("retained_other").Build());
  389. await Task.Delay(500);
  390. Assert.AreEqual(0, receivedMessagesCount);
  391. }
  392. }
  393. [TestMethod]
  394. public async Task Receive_Retained_Message_After_Subscribe()
  395. {
  396. using (var testEnvironment = new TestEnvironment())
  397. {
  398. await testEnvironment.StartServerAsync();
  399. var c1 = await testEnvironment.ConnectClientAsync();
  400. await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build());
  401. await c1.DisconnectAsync();
  402. var receivedMessages = new List<MqttApplicationMessage>();
  403. var c2 = await testEnvironment.ConnectClientAsync();
  404. c2.UseApplicationMessageReceivedHandler(c =>
  405. {
  406. lock (receivedMessages)
  407. {
  408. receivedMessages.Add(c.ApplicationMessage);
  409. }
  410. });
  411. await c2.SubscribeAsync(new TopicFilterBuilder().WithTopic("retained").Build());
  412. await Task.Delay(500);
  413. Assert.AreEqual(1, receivedMessages.Count);
  414. Assert.IsTrue(receivedMessages.First().Retain);
  415. }
  416. }
  417. [TestMethod]
  418. public async Task Clear_Retained_Message()
  419. {
  420. using (var testEnvironment = new TestEnvironment())
  421. {
  422. var receivedMessagesCount = 0;
  423. await testEnvironment.StartServerAsync();
  424. var c1 = await testEnvironment.ConnectClientAsync();
  425. await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build());
  426. await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[0]).WithRetainFlag().Build());
  427. await c1.DisconnectAsync();
  428. var c2 = await testEnvironment.ConnectClientAsync();
  429. c2.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
  430. await Task.Delay(200);
  431. await c2.SubscribeAsync(new TopicFilter { Topic = "retained", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce });
  432. await Task.Delay(500);
  433. Assert.AreEqual(0, receivedMessagesCount);
  434. }
  435. }
  436. [TestMethod]
  437. public async Task Persist_Retained_Message()
  438. {
  439. var serverStorage = new TestServerStorage();
  440. using (var testEnvironment = new TestEnvironment())
  441. {
  442. await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithStorage(serverStorage));
  443. var c1 = await testEnvironment.ConnectClientAsync();
  444. await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build());
  445. await Task.Delay(500);
  446. Assert.AreEqual(1, serverStorage.Messages.Count);
  447. }
  448. }
  449. [TestMethod]
  450. public async Task Intercept_Message()
  451. {
  452. void Interceptor(MqttApplicationMessageInterceptorContext context)
  453. {
  454. context.ApplicationMessage.Payload = Encoding.ASCII.GetBytes("extended");
  455. }
  456. using (var testEnvironment = new TestEnvironment())
  457. {
  458. await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithApplicationMessageInterceptor(Interceptor));
  459. var c1 = await testEnvironment.ConnectClientAsync();
  460. var c2 = await testEnvironment.ConnectClientAsync();
  461. await c2.SubscribeAsync(new TopicFilterBuilder().WithTopic("test").Build());
  462. var isIntercepted = false;
  463. c2.UseApplicationMessageReceivedHandler(c =>
  464. {
  465. isIntercepted = string.Compare("extended", Encoding.UTF8.GetString(c.ApplicationMessage.Payload), StringComparison.Ordinal) == 0;
  466. });
  467. await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("test").Build());
  468. await c1.DisconnectAsync();
  469. await Task.Delay(500);
  470. Assert.IsTrue(isIntercepted);
  471. }
  472. }
  473. [TestMethod]
  474. public async Task Send_Long_Body()
  475. {
  476. using (var testEnvironment = new TestEnvironment())
  477. {
  478. const int PayloadSizeInMB = 30;
  479. const int CharCount = PayloadSizeInMB * 1024 * 1024;
  480. var longBody = new byte[CharCount];
  481. byte @char = 32;
  482. for (long i = 0; i < PayloadSizeInMB * 1024L * 1024L; i++)
  483. {
  484. longBody[i] = @char;
  485. @char++;
  486. if (@char > 126)
  487. {
  488. @char = 32;
  489. }
  490. }
  491. byte[] receivedBody = null;
  492. await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder());
  493. var client1 = await testEnvironment.ConnectClientAsync();
  494. client1.UseApplicationMessageReceivedHandler(c =>
  495. {
  496. receivedBody = c.ApplicationMessage.Payload;
  497. });
  498. await client1.SubscribeAsync("string");
  499. var client2 = await testEnvironment.ConnectClientAsync();
  500. await client2.PublishAsync("string", longBody);
  501. await Task.Delay(500);
  502. Assert.IsTrue(longBody.SequenceEqual(receivedBody ?? new byte[0]));
  503. }
  504. }
  505. [TestMethod]
  506. public async Task Deny_Connection()
  507. {
  508. var serverOptions = new MqttServerOptionsBuilder().WithConnectionValidator(context =>
  509. {
  510. context.ReturnCode = MqttConnectReturnCode.ConnectionRefusedNotAuthorized;
  511. });
  512. using (var testEnvironment = new TestEnvironment())
  513. {
  514. testEnvironment.IgnoreClientLogErrors = true;
  515. await testEnvironment.StartServerAsync(serverOptions);
  516. try
  517. {
  518. await testEnvironment.ConnectClientAsync();
  519. Assert.Fail("An exception should be raised.");
  520. }
  521. catch (Exception exception)
  522. {
  523. if (exception is MqttConnectingFailedException connectingFailedException)
  524. {
  525. Assert.AreEqual(MqttClientConnectResultCode.NotAuthorized, connectingFailedException.ResultCode);
  526. }
  527. else
  528. {
  529. Assert.Fail("Wrong exception.");
  530. }
  531. }
  532. }
  533. }
  534. [TestMethod]
  535. public async Task Same_Client_Id_Connect_Disconnect_Event_Order()
  536. {
  537. using (var testEnvironment = new TestEnvironment())
  538. {
  539. var server = await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder());
  540. var events = new List<string>();
  541. server.ClientConnectedHandler = new MqttServerClientConnectedHandlerDelegate(_ =>
  542. {
  543. lock (events)
  544. {
  545. events.Add("c");
  546. }
  547. });
  548. server.ClientDisconnectedHandler = new MqttServerClientDisconnectedHandlerDelegate(_ =>
  549. {
  550. lock (events)
  551. {
  552. events.Add("d");
  553. }
  554. });
  555. var clientOptions = new MqttClientOptionsBuilder()
  556. .WithClientId("same_id");
  557. // c
  558. var c1 = await testEnvironment.ConnectClientAsync(clientOptions);
  559. await Task.Delay(500);
  560. var flow = string.Join(string.Empty, events);
  561. Assert.AreEqual("c", flow);
  562. // dc
  563. var c2 = await testEnvironment.ConnectClientAsync(clientOptions);
  564. await Task.Delay(500);
  565. flow = string.Join(string.Empty, events);
  566. Assert.AreEqual("cdc", flow);
  567. // nothing
  568. await c1.DisconnectAsync();
  569. await Task.Delay(500);
  570. // d
  571. await c2.DisconnectAsync();
  572. await Task.Delay(500);
  573. await server.StopAsync();
  574. flow = string.Join(string.Empty, events);
  575. Assert.AreEqual("cdcd", flow);
  576. }
  577. }
  578. [TestMethod]
  579. public async Task Remove_Session()
  580. {
  581. using (var testEnvironment = new TestEnvironment())
  582. {
  583. var server = await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder());
  584. var clientOptions = new MqttClientOptionsBuilder();
  585. var c1 = await testEnvironment.ConnectClientAsync(clientOptions);
  586. await Task.Delay(500);
  587. Assert.AreEqual(1, (await server.GetClientStatusAsync()).Count);
  588. await c1.DisconnectAsync();
  589. await Task.Delay(500);
  590. Assert.AreEqual(0, (await server.GetClientStatusAsync()).Count);
  591. }
  592. }
  593. [TestMethod]
  594. public async Task Stop_And_Restart()
  595. {
  596. using (var testEnvironment = new TestEnvironment())
  597. {
  598. testEnvironment.IgnoreClientLogErrors = true;
  599. var server = await testEnvironment.StartServerAsync();
  600. await testEnvironment.ConnectClientAsync();
  601. await server.StopAsync();
  602. try
  603. {
  604. await testEnvironment.ConnectClientAsync();
  605. Assert.Fail("Connecting should fail.");
  606. }
  607. catch (Exception)
  608. {
  609. }
  610. await server.StartAsync(new MqttServerOptionsBuilder().WithDefaultEndpointPort(testEnvironment.ServerPort).Build());
  611. await testEnvironment.ConnectClientAsync();
  612. }
  613. }
  614. [TestMethod]
  615. public async Task Close_Idle_Connection()
  616. {
  617. using (var testEnvironment = new TestEnvironment())
  618. {
  619. await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithDefaultCommunicationTimeout(TimeSpan.FromSeconds(1)));
  620. var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  621. await client.ConnectAsync("localhost", testEnvironment.ServerPort);
  622. // Don't send anything. The server should close the connection.
  623. await Task.Delay(TimeSpan.FromSeconds(3));
  624. try
  625. {
  626. var receivedBytes = await client.ReceiveAsync(new ArraySegment<byte>(new byte[10]), SocketFlags.Partial);
  627. if (receivedBytes == 0)
  628. {
  629. return;
  630. }
  631. Assert.Fail("Receive should throw an exception.");
  632. }
  633. catch (SocketException)
  634. {
  635. }
  636. }
  637. }
  638. [TestMethod]
  639. public async Task Send_Garbage()
  640. {
  641. using (var testEnvironment = new TestEnvironment())
  642. {
  643. await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithDefaultCommunicationTimeout(TimeSpan.FromSeconds(1)));
  644. // Send an invalid packet and ensure that the server will close the connection and stay in a waiting state
  645. // forever. This is security related.
  646. var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  647. await client.ConnectAsync("localhost", testEnvironment.ServerPort);
  648. await client.SendAsync(Encoding.UTF8.GetBytes("Garbage"), SocketFlags.None);
  649. await Task.Delay(TimeSpan.FromSeconds(3));
  650. try
  651. {
  652. var receivedBytes = await client.ReceiveAsync(new ArraySegment<byte>(new byte[10]), SocketFlags.Partial);
  653. if (receivedBytes == 0)
  654. {
  655. return;
  656. }
  657. Assert.Fail("Receive should throw an exception.");
  658. }
  659. catch (SocketException)
  660. {
  661. }
  662. }
  663. }
  664. [TestMethod]
  665. public async Task Do_Not_Send_Retained_Messages_For_Denied_Subscription()
  666. {
  667. using (var testEnvironment = new TestEnvironment())
  668. {
  669. await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithSubscriptionInterceptor(c =>
  670. {
  671. // This should lead to no subscriptions for "n" at all. So also no sending of retained messages.
  672. if (c.TopicFilter.Topic == "n")
  673. {
  674. c.AcceptSubscription = false;
  675. }
  676. }));
  677. // Prepare some retained messages.
  678. var client1 = await testEnvironment.ConnectClientAsync();
  679. await client1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("y").WithPayload("x").WithRetainFlag().Build());
  680. await client1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("n").WithPayload("x").WithRetainFlag().Build());
  681. await client1.DisconnectAsync();
  682. await Task.Delay(500);
  683. // Subscribe to all retained message types.
  684. // It is important to do this in a range of filters to ensure that a subscription is not "hidden".
  685. var client2 = await testEnvironment.ConnectClientAsync();
  686. var buffer = new StringBuilder();
  687. client2.UseApplicationMessageReceivedHandler(c =>
  688. {
  689. lock (buffer)
  690. {
  691. buffer.Append(c.ApplicationMessage.Topic);
  692. }
  693. });
  694. await client2.SubscribeAsync(new TopicFilter { Topic = "y" }, new TopicFilter { Topic = "n" });
  695. await Task.Delay(500);
  696. Assert.AreEqual("y", buffer.ToString());
  697. }
  698. }
  699. [TestMethod]
  700. public async Task Collect_Messages_In_Disconnected_Session()
  701. {
  702. using (var testEnvironment = new TestEnvironment())
  703. {
  704. var server = await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithPersistentSessions());
  705. // Create the session including the subscription.
  706. var client1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("a"));
  707. await client1.SubscribeAsync("x");
  708. await client1.DisconnectAsync();
  709. await Task.Delay(500);
  710. var clientStatus = await server.GetClientStatusAsync();
  711. Assert.AreEqual(0, clientStatus.Count);
  712. var client2 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("b"));
  713. await client2.PublishAsync("x", "1");
  714. await client2.PublishAsync("x", "2");
  715. await client2.PublishAsync("x", "3");
  716. await client2.DisconnectAsync();
  717. await Task.Delay(500);
  718. clientStatus = await server.GetClientStatusAsync();
  719. var sessionStatus = await server.GetSessionStatusAsync();
  720. Assert.AreEqual(0, clientStatus.Count);
  721. Assert.AreEqual(2, sessionStatus.Count);
  722. Assert.AreEqual(3, sessionStatus.First(s => s.ClientId == "a").PendingApplicationMessagesCount);
  723. }
  724. }
  725. private static async Task TestPublishAsync(
  726. string topic,
  727. MqttQualityOfServiceLevel qualityOfServiceLevel,
  728. string topicFilter,
  729. MqttQualityOfServiceLevel filterQualityOfServiceLevel,
  730. int expectedReceivedMessagesCount)
  731. {
  732. using (var testEnvironment = new TestEnvironment())
  733. {
  734. var receivedMessagesCount = 0;
  735. await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder());
  736. var c1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("receiver"));
  737. c1.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
  738. await c1.SubscribeAsync(new TopicFilterBuilder().WithTopic(topicFilter).WithQualityOfServiceLevel(filterQualityOfServiceLevel).Build());
  739. var c2 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("sender"));
  740. await c2.PublishAsync(new MqttApplicationMessageBuilder().WithTopic(topic).WithPayload(new byte[0]).WithQualityOfServiceLevel(qualityOfServiceLevel).Build());
  741. await c2.DisconnectAsync().ConfigureAwait(false);
  742. await Task.Delay(500);
  743. await c1.UnsubscribeAsync(topicFilter);
  744. await Task.Delay(500);
  745. Assert.AreEqual(expectedReceivedMessagesCount, receivedMessagesCount);
  746. }
  747. }
  748. }
  749. }