Refactor subscriptions manager

This commit is contained in:
Christian
2018-05-03 22:22:07 +02:00
parent d14088512b
commit b22b02a0b6
12 changed files with 269 additions and 107 deletions
@@ -0,0 +1,34 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Internal;
namespace MQTTnet.Core.Tests
{
[TestClass]
public class AsyncAutoResetEventTests
{
[TestMethod]
public async Task AsyncAutoResetEvent()
{
var aare = new AsyncAutoResetEvent();
var increment = 0;
var globalI = 0;
#pragma warning disable 4014
Task.Run(async () =>
#pragma warning restore 4014
{
await aare.WaitOneAsync(CancellationToken.None);
globalI += increment;
});
await Task.Delay(500);
increment = 1;
aare.Set();
await Task.Delay(100);
Assert.AreEqual(1, globalI);
}
}
}
@@ -0,0 +1,44 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Internal;
namespace MQTTnet.Core.Tests
{
[TestClass]
public class AsyncLockTests
{
[TestMethod]
public void AsyncLock()
{
const int ThreadsCount = 10;
var threads = new Task[ThreadsCount];
var @lock = new AsyncLock();
var globalI = 0;
for (var i = 0; i < ThreadsCount; i++)
{
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
threads[i] = Task.Run(async () =>
{
await @lock.EnterAsync(CancellationToken.None);
try
{
var localI = globalI;
await Task.Delay(10); // Increase the chance for wrong data.
localI++;
globalI = localI;
}
finally
{
@lock.Exit();
}
});
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
}
Task.WaitAll(threads);
Assert.AreEqual(ThreadsCount, globalI);
}
}
}
+56 -21
View File
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Diagnostics;
@@ -58,8 +59,8 @@ namespace MQTTnet.Core.Tests
await s.StartAsync(new MqttServerOptions());
var willMessage = new MqttApplicationMessageBuilder().WithTopic("My/last/will").WithAtMostOnceQoS().Build();
var c1 = await serverAdapter.ConnectTestClient(s, "c1");
var c2 = await serverAdapter.ConnectTestClient(s, "c2", willMessage);
var c1 = await serverAdapter.ConnectTestClient("c1");
var c2 = await serverAdapter.ConnectTestClient("c2", willMessage);
c1.ApplicationMessageReceived += (_, __) => receivedMessagesCount++;
await c1.SubscribeAsync(new TopicFilterBuilder().WithTopic("#").Build());
@@ -90,8 +91,8 @@ namespace MQTTnet.Core.Tests
{
await s.StartAsync(new MqttServerOptions());
var c1 = await serverAdapter.ConnectTestClient(s, "c1");
var c2 = await serverAdapter.ConnectTestClient(s, "c2");
var c1 = await serverAdapter.ConnectTestClient("c1");
var c2 = await serverAdapter.ConnectTestClient("c2");
c1.ApplicationMessageReceived += (_, __) => receivedMessagesCount++;
var message = new MqttApplicationMessageBuilder().WithTopic("a").WithAtLeastOnceQoS().Build();
@@ -149,7 +150,7 @@ namespace MQTTnet.Core.Tests
{
await s.StartAsync(new MqttServerOptions());
var c1 = await serverAdapter.ConnectTestClient(s, "c1");
var c1 = await serverAdapter.ConnectTestClient("c1");
c1.ApplicationMessageReceived += (_, __) => receivedMessagesCount++;
@@ -167,6 +168,40 @@ namespace MQTTnet.Core.Tests
Assert.AreEqual(1, receivedMessagesCount);
}
[TestMethod]
public async Task MqttServer_RetainedMessagesFlow()
{
var retainedMessage = new MqttApplicationMessageBuilder().WithTopic("r").WithPayload("r").WithRetainFlag().Build();
var serverAdapter = new TestMqttServerAdapter();
var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
await s.StartAsync(new MqttServerOptions());
var c1 = await serverAdapter.ConnectTestClient("c1");
await c1.PublishAsync(retainedMessage);
Thread.Sleep(500);
await c1.DisconnectAsync();
Thread.Sleep(500);
var receivedMessages = 0;
var c2 = await serverAdapter.ConnectTestClient("c2");
c2.ApplicationMessageReceived += (_, e) =>
{
receivedMessages++;
};
for (var i = 0; i < 5; i++)
{
await c2.UnsubscribeAsync("r");
await Task.Delay(500);
Assert.AreEqual(i, receivedMessages);
await c2.SubscribeAsync("r");
await Task.Delay(500);
Assert.AreEqual(i + 1, receivedMessages);
}
await c2.DisconnectAsync();
}
[TestMethod]
public async Task MqttServer_NoRetainedMessage()
{
@@ -179,11 +214,11 @@ namespace MQTTnet.Core.Tests
{
await s.StartAsync(new MqttServerOptions());
var c1 = await serverAdapter.ConnectTestClient(s, "c1");
var c1 = await serverAdapter.ConnectTestClient("c1");
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).Build());
await c1.DisconnectAsync();
var c2 = await serverAdapter.ConnectTestClient(s, "c2");
var c2 = await serverAdapter.ConnectTestClient("c2");
c2.ApplicationMessageReceived += (_, __) => receivedMessagesCount++;
await c2.SubscribeAsync(new TopicFilterBuilder().WithTopic("retained").Build());
@@ -208,11 +243,11 @@ namespace MQTTnet.Core.Tests
{
await s.StartAsync(new MqttServerOptions());
var c1 = await serverAdapter.ConnectTestClient(s, "c1");
var c1 = await serverAdapter.ConnectTestClient("c1");
await c1.PublishAndWaitForAsync(s, new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build());
await c1.DisconnectAsync();
var c2 = await serverAdapter.ConnectTestClient(s, "c2");
var c2 = await serverAdapter.ConnectTestClient("c2");
c2.ApplicationMessageReceived += (_, __) => receivedMessagesCount++;
await c2.SubscribeAsync(new TopicFilterBuilder().WithTopic("retained").Build());
@@ -237,14 +272,14 @@ namespace MQTTnet.Core.Tests
{
await s.StartAsync(new MqttServerOptions());
var c1 = await serverAdapter.ConnectTestClient(s, "c1");
var c1 = await serverAdapter.ConnectTestClient("c1");
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build());
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[0]).WithRetainFlag().Build());
await c1.DisconnectAsync();
var c2 = await serverAdapter.ConnectTestClient(s, "c2");
var c2 = await serverAdapter.ConnectTestClient("c2");
c2.ApplicationMessageReceived += (_, __) => receivedMessagesCount++;
await Task.Delay(200);
await c2.SubscribeAsync(new TopicFilter("retained", MqttQualityOfServiceLevel.AtMostOnce));
await Task.Delay(500);
@@ -271,7 +306,7 @@ namespace MQTTnet.Core.Tests
await s.StartAsync(options);
var c1 = await serverAdapter.ConnectTestClient(s, "c1");
var c1 = await serverAdapter.ConnectTestClient("c1");
await c1.PublishAndWaitForAsync(s, new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build());
await c1.DisconnectAsync();
@@ -291,7 +326,7 @@ namespace MQTTnet.Core.Tests
var options = new MqttServerOptions { Storage = storage };
await s.StartAsync(options);
var c2 = await serverAdapter.ConnectTestClient(s, "c2");
var c2 = await serverAdapter.ConnectTestClient("c2");
c2.ApplicationMessageReceived += (_, __) => receivedMessagesCount++;
await c2.SubscribeAsync(new TopicFilterBuilder().WithTopic("retained").Build());
@@ -322,8 +357,8 @@ namespace MQTTnet.Core.Tests
await s.StartAsync(options);
var c1 = await serverAdapter.ConnectTestClient(s, "c1");
var c2 = await serverAdapter.ConnectTestClient(s, "c2");
var c1 = await serverAdapter.ConnectTestClient("c1");
var c2 = await serverAdapter.ConnectTestClient("c2");
await c2.SubscribeAsync(new TopicFilterBuilder().WithTopic("test").Build());
var isIntercepted = false;
@@ -357,8 +392,8 @@ namespace MQTTnet.Core.Tests
{
await s.StartAsync(new MqttServerOptions());
var c1 = await serverAdapter.ConnectTestClient(s, "c1");
var c2 = await serverAdapter.ConnectTestClient(s, "c2");
var c1 = await serverAdapter.ConnectTestClient("c1");
var c2 = await serverAdapter.ConnectTestClient("c2");
c1.ApplicationMessageReceived += (_, e) =>
{
@@ -412,8 +447,8 @@ namespace MQTTnet.Core.Tests
{
await s.StartAsync(new MqttServerOptions());
var c1 = await serverAdapter.ConnectTestClient(s, "c1");
var c2 = await serverAdapter.ConnectTestClient(s, "c2");
var c1 = await serverAdapter.ConnectTestClient("c1");
var c2 = await serverAdapter.ConnectTestClient("c2");
c1.ApplicationMessageReceived += (_, __) => receivedMessagesCount++;
@@ -18,7 +18,7 @@ namespace MQTTnet.Core.Tests
var sp = new MqttSubscribePacket();
sp.TopicFilters.Add(new TopicFilterBuilder().WithTopic("A/B/C").Build());
sm.SubscribeAsync(sp).Wait();
sm.Subscribe(sp);
var pp = new MqttApplicationMessage
{
@@ -39,7 +39,7 @@ namespace MQTTnet.Core.Tests
var sp = new MqttSubscribePacket();
sp.TopicFilters.Add(new TopicFilter("A/B/C", MqttQualityOfServiceLevel.AtMostOnce));
sm.SubscribeAsync(sp).Wait();
sm.Subscribe(sp);
var pp = new MqttApplicationMessage
{
@@ -61,7 +61,7 @@ namespace MQTTnet.Core.Tests
sp.TopicFilters.Add(new TopicFilter("#", MqttQualityOfServiceLevel.AtMostOnce));
sp.TopicFilters.Add(new TopicFilter("A/B/C", MqttQualityOfServiceLevel.AtLeastOnce));
sm.SubscribeAsync(sp).Wait();
sm.Subscribe(sp);
var pp = new MqttApplicationMessage
{
@@ -82,7 +82,7 @@ namespace MQTTnet.Core.Tests
var sp = new MqttSubscribePacket();
sp.TopicFilters.Add(new TopicFilterBuilder().WithTopic("A/B/C").Build());
sm.SubscribeAsync(sp).Wait();
sm.Subscribe(sp);
var pp = new MqttApplicationMessage
{
@@ -101,7 +101,7 @@ namespace MQTTnet.Core.Tests
var sp = new MqttSubscribePacket();
sp.TopicFilters.Add(new TopicFilterBuilder().WithTopic("A/B/C").Build());
sm.SubscribeAsync(sp).Wait();
sm.Subscribe(sp);
var pp = new MqttApplicationMessage
{
@@ -113,7 +113,7 @@ namespace MQTTnet.Core.Tests
var up = new MqttUnsubscribePacket();
up.TopicFilters.Add("A/B/C");
sm.UnsubscribeAsync(up).Wait();
sm.Unsubscribe(up);
Assert.IsFalse(sm.CheckSubscriptionsAsync(pp).Result.IsSubscribed);
}
@@ -43,11 +43,30 @@ namespace MQTTnet.Core.Tests
return Task.FromResult(0);
}
public Task<MqttBasePacket> ReceivePacketAsync(TimeSpan timeout, CancellationToken cancellationToken)
public async Task<MqttBasePacket> ReceivePacketAsync(TimeSpan timeout, CancellationToken cancellationToken)
{
ThrowIfPartnerIsNull();
return Task.Run(() =>
if (timeout > TimeSpan.Zero)
{
using (var timeoutCts = new CancellationTokenSource(timeout))
using (var cts = CancellationTokenSource.CreateLinkedTokenSource(timeoutCts.Token, cancellationToken))
{
return await Task.Run(() =>
{
try
{
return _incomingPackets.Take(cts.Token);
}
catch
{
return null;
}
}, cts.Token);
}
}
return await Task.Run(() =>
{
try
{
@@ -1,4 +1,5 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Adapter;
using MQTTnet.Client;
@@ -11,7 +12,7 @@ namespace MQTTnet.Core.Tests
{
public event EventHandler<MqttServerAdapterClientAcceptedEventArgs> ClientAccepted;
public async Task<IMqttClient> ConnectTestClient(IMqttServer server, string clientId, MqttApplicationMessage willMessage = null)
public async Task<IMqttClient> ConnectTestClient(string clientId, MqttApplicationMessage willMessage = null)
{
var adapterA = new TestMqttCommunicationAdapter();
var adapterB = new TestMqttCommunicationAdapter();
@@ -22,8 +23,6 @@ namespace MQTTnet.Core.Tests
new TestMqttCommunicationAdapterFactory(adapterA),
new MqttNetLogger());
var connected = WaitForClientToConnect(server, clientId);
FireClientAcceptedEvent(adapterB);
var options = new MqttClientOptions
@@ -34,29 +33,11 @@ namespace MQTTnet.Core.Tests
};
await client.ConnectAsync(options);
await connected;
SpinWait.SpinUntil(() => client.IsConnected);
return client;
}
private static Task WaitForClientToConnect(IMqttServer s, string clientId)
{
var tcs = new TaskCompletionSource<object>();
void Handler(object sender, Server.MqttClientConnectedEventArgs args)
{
if (args.Client.ClientId == clientId)
{
s.ClientConnected -= Handler;
tcs.SetResult(null);
}
}
s.ClientConnected += Handler;
return tcs.Task;
}
private void FireClientAcceptedEvent(IMqttChannelAdapter adapter)
{
ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(adapter));