您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

656 行
22 KiB

  1. using Microsoft.VisualStudio.TestTools.UnitTesting;
  2. using MQTTnet.Client;
  3. using MQTTnet.Diagnostics;
  4. using MQTTnet.Protocol;
  5. using MQTTnet.Server;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Text;
  9. using System.Threading;
  10. using System.Threading.Tasks;
  11. using MQTTnet.Implementations;
  12. namespace MQTTnet.Core.Tests
  13. {
  14. [TestClass]
  15. public class MqttServerTests
  16. {
  17. [TestMethod]
  18. public void MqttServer_PublishSimple_AtMostOnce()
  19. {
  20. TestPublishAsync(
  21. "A/B/C",
  22. MqttQualityOfServiceLevel.AtMostOnce,
  23. "A/B/C",
  24. MqttQualityOfServiceLevel.AtMostOnce,
  25. 1).Wait();
  26. }
  27. [TestMethod]
  28. public void MqttServer_PublishSimple_AtLeastOnce()
  29. {
  30. TestPublishAsync(
  31. "A/B/C",
  32. MqttQualityOfServiceLevel.AtLeastOnce,
  33. "A/B/C",
  34. MqttQualityOfServiceLevel.AtLeastOnce,
  35. 1).Wait();
  36. }
  37. [TestMethod]
  38. public void MqttServer_PublishSimple_ExactlyOnce()
  39. {
  40. TestPublishAsync(
  41. "A/B/C",
  42. MqttQualityOfServiceLevel.ExactlyOnce,
  43. "A/B/C",
  44. MqttQualityOfServiceLevel.ExactlyOnce,
  45. 1).Wait();
  46. }
  47. [TestMethod]
  48. public async Task MqttServer_WillMessage()
  49. {
  50. var serverAdapter = new TestMqttServerAdapter();
  51. var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
  52. var receivedMessagesCount = 0;
  53. try
  54. {
  55. await s.StartAsync(new MqttServerOptions());
  56. var willMessage = new MqttApplicationMessageBuilder().WithTopic("My/last/will").WithAtMostOnceQoS().Build();
  57. var c1 = await serverAdapter.ConnectTestClient("c1");
  58. var c2 = await serverAdapter.ConnectTestClient("c2", willMessage);
  59. c1.ApplicationMessageReceived += (_, __) => receivedMessagesCount++;
  60. await c1.SubscribeAsync(new TopicFilterBuilder().WithTopic("#").Build());
  61. await c2.DisconnectAsync();
  62. await Task.Delay(1000);
  63. await c1.DisconnectAsync();
  64. }
  65. finally
  66. {
  67. await s.StopAsync();
  68. }
  69. Assert.AreEqual(0, receivedMessagesCount);
  70. }
  71. [TestMethod]
  72. public async Task MqttServer_SubscribeUnsubscribe()
  73. {
  74. var serverAdapter = new TestMqttServerAdapter();
  75. var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
  76. var receivedMessagesCount = 0;
  77. try
  78. {
  79. await s.StartAsync(new MqttServerOptions());
  80. var c1 = await serverAdapter.ConnectTestClient("c1");
  81. var c2 = await serverAdapter.ConnectTestClient("c2");
  82. c1.ApplicationMessageReceived += (_, __) => receivedMessagesCount++;
  83. var message = new MqttApplicationMessageBuilder().WithTopic("a").WithAtLeastOnceQoS().Build();
  84. await c2.PublishAsync(message);
  85. await Task.Delay(1000);
  86. Assert.AreEqual(0, receivedMessagesCount);
  87. var subscribeEventCalled = false;
  88. s.ClientSubscribedTopic += (_, e) =>
  89. {
  90. subscribeEventCalled = e.TopicFilter.Topic == "a" && e.ClientId == "c1";
  91. };
  92. await c1.SubscribeAsync(new TopicFilter("a", MqttQualityOfServiceLevel.AtLeastOnce));
  93. await Task.Delay(500);
  94. Assert.IsTrue(subscribeEventCalled, "Subscribe event not called.");
  95. await c2.PublishAsync(message);
  96. await Task.Delay(500);
  97. Assert.AreEqual(1, receivedMessagesCount);
  98. var unsubscribeEventCalled = false;
  99. s.ClientUnsubscribedTopic += (_, e) =>
  100. {
  101. unsubscribeEventCalled = e.TopicFilter == "a" && e.ClientId == "c1";
  102. };
  103. await c1.UnsubscribeAsync("a");
  104. await Task.Delay(500);
  105. Assert.IsTrue(unsubscribeEventCalled, "Unsubscribe event not called.");
  106. await c2.PublishAsync(message);
  107. await Task.Delay(1000);
  108. Assert.AreEqual(1, receivedMessagesCount);
  109. }
  110. finally
  111. {
  112. await s.StopAsync();
  113. }
  114. await Task.Delay(500);
  115. Assert.AreEqual(1, receivedMessagesCount);
  116. }
  117. [TestMethod]
  118. public async Task MqttServer_Publish()
  119. {
  120. var serverAdapter = new TestMqttServerAdapter();
  121. var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
  122. var receivedMessagesCount = 0;
  123. try
  124. {
  125. await s.StartAsync(new MqttServerOptions());
  126. var c1 = await serverAdapter.ConnectTestClient("c1");
  127. c1.ApplicationMessageReceived += (_, __) => receivedMessagesCount++;
  128. var message = new MqttApplicationMessageBuilder().WithTopic("a").WithAtLeastOnceQoS().Build();
  129. await c1.SubscribeAsync(new TopicFilter("a", MqttQualityOfServiceLevel.AtLeastOnce));
  130. await s.PublishAsync(message);
  131. await Task.Delay(500);
  132. }
  133. finally
  134. {
  135. await s.StopAsync();
  136. }
  137. Assert.AreEqual(1, receivedMessagesCount);
  138. }
  139. [TestMethod]
  140. public async Task MqttServer_Publish_MultipleClients()
  141. {
  142. var serverAdapter = new MqttTcpServerAdapter(new MqttNetLogger().CreateChildLogger());
  143. var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
  144. var receivedMessagesCount = 0;
  145. var locked = new object();
  146. var clientOptions = new MqttClientOptionsBuilder()
  147. .WithTcpServer("localhost")
  148. .Build();
  149. var clientOptions2 = new MqttClientOptionsBuilder()
  150. .WithTcpServer("localhost")
  151. .Build();
  152. try
  153. {
  154. await s.StartAsync(new MqttServerOptions());
  155. var c1 = new MqttFactory().CreateMqttClient();
  156. var c2 = new MqttFactory().CreateMqttClient();
  157. await c1.ConnectAsync(clientOptions);
  158. await c2.ConnectAsync(clientOptions2);
  159. c1.ApplicationMessageReceived += (_, __) =>
  160. {
  161. lock (locked)
  162. {
  163. receivedMessagesCount++;
  164. }
  165. };
  166. c2.ApplicationMessageReceived += (_, __) =>
  167. {
  168. lock (locked)
  169. {
  170. receivedMessagesCount++;
  171. }
  172. };
  173. var message = new MqttApplicationMessageBuilder().WithTopic("a").WithAtLeastOnceQoS().Build();
  174. await c1.SubscribeAsync(new TopicFilter("a", MqttQualityOfServiceLevel.AtLeastOnce));
  175. await c2.SubscribeAsync(new TopicFilter("a", MqttQualityOfServiceLevel.AtLeastOnce));
  176. //await Task.WhenAll(Publish(c1, message), Publish(c2, message));
  177. await Publish(c1, message);
  178. await Task.Delay(500);
  179. }
  180. finally
  181. {
  182. await s.StopAsync();
  183. }
  184. Assert.AreEqual(2000, receivedMessagesCount);
  185. }
  186. private static async Task Publish(IMqttClient c1, MqttApplicationMessage message)
  187. {
  188. for (int i = 0; i < 1000; i++)
  189. {
  190. await c1.PublishAsync(message);
  191. }
  192. }
  193. [TestMethod]
  194. public async Task MqttServer_ShutdownDisconnectsClientsGracefully()
  195. {
  196. var serverAdapter = new MqttTcpServerAdapter(new MqttNetLogger().CreateChildLogger());
  197. var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
  198. var clientOptions = new MqttClientOptionsBuilder()
  199. .WithTcpServer("localhost")
  200. .Build();
  201. var disconnectCalled = 0;
  202. await s.StartAsync(new MqttServerOptions());
  203. var c1 = new MqttFactory().CreateMqttClient();
  204. c1.Disconnected += (sender, args) => disconnectCalled++;
  205. await c1.ConnectAsync(clientOptions);
  206. await Task.Delay(100);
  207. await s.StopAsync();
  208. await Task.Delay(100);
  209. Assert.AreEqual(1, disconnectCalled);
  210. }
  211. [TestMethod]
  212. public async Task MqttServer_HandleCleanDisconnect()
  213. {
  214. MqttNetGlobalLogger.LogMessagePublished += (_, e) =>
  215. {
  216. System.Diagnostics.Debug.WriteLine($"[{e.TraceMessage.Timestamp:s}] {e.TraceMessage.Source} {e.TraceMessage.Message}");
  217. };
  218. var serverAdapter = new MqttTcpServerAdapter(new MqttNetLogger().CreateChildLogger());
  219. var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
  220. var clientConnectedCalled = 0;
  221. var clientDisconnectedCalled = 0;
  222. s.ClientConnected += (_, __) => clientConnectedCalled++;
  223. s.ClientDisconnected += (_, __) => clientDisconnectedCalled++;
  224. var clientOptions = new MqttClientOptionsBuilder()
  225. .WithTcpServer("localhost")
  226. .Build();
  227. await s.StartAsync(new MqttServerOptions());
  228. var c1 = new MqttFactory().CreateMqttClient();
  229. await c1.ConnectAsync(clientOptions);
  230. await Task.Delay(100);
  231. await c1.DisconnectAsync();
  232. await Task.Delay(100);
  233. await s.StopAsync();
  234. await Task.Delay(100);
  235. Assert.AreEqual(clientConnectedCalled, clientDisconnectedCalled);
  236. }
  237. [TestMethod]
  238. public async Task MqttServer_RetainedMessagesFlow()
  239. {
  240. var retainedMessage = new MqttApplicationMessageBuilder().WithTopic("r").WithPayload("r").WithRetainFlag().Build();
  241. var serverAdapter = new TestMqttServerAdapter();
  242. var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
  243. await s.StartAsync(new MqttServerOptions());
  244. var c1 = await serverAdapter.ConnectTestClient("c1");
  245. await c1.PublishAsync(retainedMessage);
  246. Thread.Sleep(500);
  247. await c1.DisconnectAsync();
  248. Thread.Sleep(500);
  249. var receivedMessages = 0;
  250. var c2 = await serverAdapter.ConnectTestClient("c2");
  251. c2.ApplicationMessageReceived += (_, e) =>
  252. {
  253. receivedMessages++;
  254. };
  255. for (var i = 0; i < 5; i++)
  256. {
  257. await c2.UnsubscribeAsync("r");
  258. await Task.Delay(500);
  259. Assert.AreEqual(i, receivedMessages);
  260. await c2.SubscribeAsync("r");
  261. await Task.Delay(500);
  262. Assert.AreEqual(i + 1, receivedMessages);
  263. }
  264. await c2.DisconnectAsync();
  265. }
  266. [TestMethod]
  267. public async Task MqttServer_NoRetainedMessage()
  268. {
  269. var serverAdapter = new TestMqttServerAdapter();
  270. var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
  271. var receivedMessagesCount = 0;
  272. try
  273. {
  274. await s.StartAsync(new MqttServerOptions());
  275. var c1 = await serverAdapter.ConnectTestClient("c1");
  276. await c1.PublishAsync(builder => builder.WithTopic("retained").WithPayload(new byte[3]));
  277. await c1.DisconnectAsync();
  278. var c2 = await serverAdapter.ConnectTestClient("c2");
  279. c2.ApplicationMessageReceived += (_, __) => receivedMessagesCount++;
  280. await c2.SubscribeAsync(new TopicFilterBuilder().WithTopic("retained").Build());
  281. await Task.Delay(500);
  282. }
  283. finally
  284. {
  285. await s.StopAsync();
  286. }
  287. Assert.AreEqual(0, receivedMessagesCount);
  288. }
  289. [TestMethod]
  290. public async Task MqttServer_RetainedMessage()
  291. {
  292. var serverAdapter = new TestMqttServerAdapter();
  293. var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
  294. var receivedMessagesCount = 0;
  295. try
  296. {
  297. await s.StartAsync(new MqttServerOptions());
  298. var c1 = await serverAdapter.ConnectTestClient("c1");
  299. await c1.PublishAndWaitForAsync(s, new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build());
  300. await c1.DisconnectAsync();
  301. var c2 = await serverAdapter.ConnectTestClient("c2");
  302. c2.ApplicationMessageReceived += (_, __) => receivedMessagesCount++;
  303. await c2.SubscribeAsync(new TopicFilterBuilder().WithTopic("retained").Build());
  304. await Task.Delay(500);
  305. }
  306. finally
  307. {
  308. await s.StopAsync();
  309. }
  310. Assert.AreEqual(1, receivedMessagesCount);
  311. }
  312. [TestMethod]
  313. public async Task MqttServer_ClearRetainedMessage()
  314. {
  315. var serverAdapter = new TestMqttServerAdapter();
  316. var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
  317. var receivedMessagesCount = 0;
  318. try
  319. {
  320. await s.StartAsync(new MqttServerOptions());
  321. var c1 = await serverAdapter.ConnectTestClient("c1");
  322. await c1.PublishAsync(builder => builder.WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag());
  323. await c1.PublishAsync(builder => builder.WithTopic("retained").WithPayload(new byte[0]).WithRetainFlag());
  324. await c1.DisconnectAsync();
  325. var c2 = await serverAdapter.ConnectTestClient("c2");
  326. c2.ApplicationMessageReceived += (_, __) => receivedMessagesCount++;
  327. await Task.Delay(200);
  328. await c2.SubscribeAsync(new TopicFilter("retained", MqttQualityOfServiceLevel.AtMostOnce));
  329. await Task.Delay(500);
  330. }
  331. finally
  332. {
  333. await s.StopAsync();
  334. }
  335. Assert.AreEqual(0, receivedMessagesCount);
  336. }
  337. [TestMethod]
  338. public async Task MqttServer_PersistRetainedMessage()
  339. {
  340. var storage = new TestStorage();
  341. var serverAdapter = new TestMqttServerAdapter();
  342. var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
  343. try
  344. {
  345. var options = new MqttServerOptions { Storage = storage };
  346. await s.StartAsync(options);
  347. var c1 = await serverAdapter.ConnectTestClient("c1");
  348. await c1.PublishAndWaitForAsync(s, new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build());
  349. await Task.Delay(250);
  350. await c1.DisconnectAsync();
  351. }
  352. finally
  353. {
  354. await s.StopAsync();
  355. }
  356. Assert.AreEqual(1, storage.Messages.Count);
  357. s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
  358. var receivedMessagesCount = 0;
  359. try
  360. {
  361. var options = new MqttServerOptions { Storage = storage };
  362. await s.StartAsync(options);
  363. var c2 = await serverAdapter.ConnectTestClient("c2");
  364. c2.ApplicationMessageReceived += (_, __) => receivedMessagesCount++;
  365. await c2.SubscribeAsync(new TopicFilterBuilder().WithTopic("retained").Build());
  366. await Task.Delay(250);
  367. }
  368. finally
  369. {
  370. await s.StopAsync();
  371. }
  372. Assert.AreEqual(1, receivedMessagesCount);
  373. }
  374. [TestMethod]
  375. public async Task MqttServer_InterceptMessage()
  376. {
  377. void Interceptor(MqttApplicationMessageInterceptorContext context)
  378. {
  379. context.ApplicationMessage.Payload = Encoding.ASCII.GetBytes("extended");
  380. }
  381. var serverAdapter = new TestMqttServerAdapter();
  382. var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
  383. try
  384. {
  385. var options = new MqttServerOptions { ApplicationMessageInterceptor = Interceptor };
  386. await s.StartAsync(options);
  387. var c1 = await serverAdapter.ConnectTestClient("c1");
  388. var c2 = await serverAdapter.ConnectTestClient("c2");
  389. await c2.SubscribeAsync(new TopicFilterBuilder().WithTopic("test").Build());
  390. var isIntercepted = false;
  391. c2.ApplicationMessageReceived += (sender, args) =>
  392. {
  393. isIntercepted = string.Compare("extended", Encoding.UTF8.GetString(args.ApplicationMessage.Payload), StringComparison.Ordinal) == 0;
  394. };
  395. await c1.PublishAsync(builder => builder.WithTopic("test"));
  396. await c1.DisconnectAsync();
  397. await Task.Delay(500);
  398. Assert.IsTrue(isIntercepted);
  399. }
  400. finally
  401. {
  402. await s.StopAsync();
  403. }
  404. }
  405. [TestMethod]
  406. public async Task MqttServer_Body()
  407. {
  408. var serverAdapter = new TestMqttServerAdapter();
  409. var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
  410. var bodyIsMatching = false;
  411. try
  412. {
  413. await s.StartAsync(new MqttServerOptions());
  414. var c1 = await serverAdapter.ConnectTestClient("c1");
  415. var c2 = await serverAdapter.ConnectTestClient("c2");
  416. c1.ApplicationMessageReceived += (_, e) =>
  417. {
  418. if (Encoding.UTF8.GetString(e.ApplicationMessage.Payload) == "The body")
  419. {
  420. bodyIsMatching = true;
  421. }
  422. };
  423. await c1.SubscribeAsync("A", MqttQualityOfServiceLevel.AtMostOnce);
  424. await c2.PublishAsync(builder => builder.WithTopic("A").WithPayload(Encoding.UTF8.GetBytes("The body")));
  425. await Task.Delay(1000);
  426. }
  427. finally
  428. {
  429. await s.StopAsync();
  430. }
  431. Assert.IsTrue(bodyIsMatching);
  432. }
  433. [TestMethod]
  434. public async Task MqttServer_SameClientIdConnectDisconnectEventOrder()
  435. {
  436. var serverAdapter = new MqttTcpServerAdapter(new MqttNetLogger().CreateChildLogger());
  437. var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
  438. var connectedClient = false;
  439. var connecteCalledBeforeConnectedClients = false;
  440. s.ClientConnected += (_, __) =>
  441. {
  442. connecteCalledBeforeConnectedClients |= connectedClient;
  443. connectedClient = true;
  444. };
  445. s.ClientDisconnected += (_, __) =>
  446. {
  447. connectedClient = false;
  448. };
  449. var clientOptions = new MqttClientOptionsBuilder()
  450. .WithTcpServer("localhost")
  451. .WithClientId(Guid.NewGuid().ToString())
  452. .Build();
  453. await s.StartAsync(new MqttServerOptions());
  454. var c1 = new MqttFactory().CreateMqttClient();
  455. var c2 = new MqttFactory().CreateMqttClient();
  456. await c1.ConnectAsync(clientOptions);
  457. await Task.Delay(100);
  458. await c2.ConnectAsync(clientOptions);
  459. await Task.Delay(100);
  460. await c1.DisconnectAsync();
  461. await c2.DisconnectAsync();
  462. await s.StopAsync();
  463. await Task.Delay(100);
  464. Assert.IsFalse(connecteCalledBeforeConnectedClients, "ClientConnected was called before ClientDisconnect was called");
  465. }
  466. private class TestStorage : IMqttServerStorage
  467. {
  468. public IList<MqttApplicationMessage> Messages = new List<MqttApplicationMessage>();
  469. public Task SaveRetainedMessagesAsync(IList<MqttApplicationMessage> messages)
  470. {
  471. Messages = messages;
  472. return Task.CompletedTask;
  473. }
  474. public Task<IList<MqttApplicationMessage>> LoadRetainedMessagesAsync()
  475. {
  476. return Task.FromResult(Messages);
  477. }
  478. }
  479. private static async Task TestPublishAsync(
  480. string topic,
  481. MqttQualityOfServiceLevel qualityOfServiceLevel,
  482. string topicFilter,
  483. MqttQualityOfServiceLevel filterQualityOfServiceLevel,
  484. int expectedReceivedMessagesCount)
  485. {
  486. var serverAdapter = new TestMqttServerAdapter();
  487. var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
  488. var receivedMessagesCount = 0;
  489. try
  490. {
  491. await s.StartAsync(new MqttServerOptions());
  492. var c1 = await serverAdapter.ConnectTestClient("c1");
  493. var c2 = await serverAdapter.ConnectTestClient("c2");
  494. c1.ApplicationMessageReceived += (_, __) => receivedMessagesCount++;
  495. await c1.SubscribeAsync(new TopicFilterBuilder().WithTopic(topicFilter).WithQualityOfServiceLevel(filterQualityOfServiceLevel).Build());
  496. await c2.PublishAsync(builder => builder.WithTopic(topic).WithPayload(new byte[0]).WithQualityOfServiceLevel(qualityOfServiceLevel));
  497. await Task.Delay(500);
  498. await c1.UnsubscribeAsync(topicFilter);
  499. await Task.Delay(500);
  500. }
  501. finally
  502. {
  503. await s.StopAsync();
  504. }
  505. Assert.AreEqual(expectedReceivedMessagesCount, receivedMessagesCount);
  506. }
  507. }
  508. }