Extend interceptors.

This commit is contained in:
Christian
2021-10-10 10:56:14 +02:00
parent db00682c75
commit 8c9460337f
23 changed files with 590 additions and 119 deletions
@@ -0,0 +1,98 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Internal;
namespace MQTTnet.Tests.Internal
{
[TestClass]
public class AsyncLock_Tests
{
[TestMethod]
public async Task Lock_Serial_Calls()
{
var sum = 0;
var @lock = new AsyncLock();
for (var i = 0; i < 100; i++)
{
using (await @lock.WaitAsync(CancellationToken.None).ConfigureAwait(false))
{
sum++;
}
}
Assert.AreEqual(100, sum);
}
[TestMethod]
[ExpectedException(typeof(TaskCanceledException))]
public async Task Test_Cancellation()
{
var @lock = new AsyncLock();
// This call will never "release" the lock due to missing _using_.
await @lock.WaitAsync(CancellationToken.None).ConfigureAwait(false);
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(3)))
{
await @lock.WaitAsync(cts.Token).ConfigureAwait(false);
}
}
//[TestMethod]
//public async Task Test_Cancellation_With_Later_Access()
//{
// var @lock = new AsyncLock();
// var releaser = await @lock.WaitAsync().ConfigureAwait(false);
// try
// {
// using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(3)))
// {
// await @lock.WaitAsync(cts.Token).ConfigureAwait(false);
// }
// }
// catch (OperationCanceledException)
// {
// }
// releaser.Dispose();
// using (await @lock.WaitAsync().ConfigureAwait(false))
// {
// // When the method finished, the thread got access.
// }
//}
[TestMethod]
public void Lock_10_Parallel_Tasks()
{
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 () =>
{
using (var releaser = await @lock.WaitAsync(CancellationToken.None))
{
var localI = globalI;
await Task.Delay(10); // Increase the chance for wrong data.
localI++;
globalI = localI;
}
});
#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);
}
}
}
@@ -0,0 +1,141 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Internal;
namespace MQTTnet.Tests.Internal
{
[TestClass]
public class AsyncQueue_Tests
{
[TestMethod]
public async Task Preserve_Order()
{
var queue = new AsyncQueue<string>();
queue.Enqueue("1");
queue.Enqueue("2");
queue.Enqueue("3");
Assert.AreEqual("1", (await queue.TryDequeueAsync(CancellationToken.None)).Item);
Assert.AreEqual("2", (await queue.TryDequeueAsync(CancellationToken.None)).Item);
Assert.AreEqual("3", (await queue.TryDequeueAsync(CancellationToken.None)).Item);
}
[TestMethod]
public void Count()
{
var queue = new AsyncQueue<string>();
queue.Enqueue("1");
Assert.AreEqual(1, queue.Count);
queue.Enqueue("2");
Assert.AreEqual(2, queue.Count);
queue.Enqueue("3");
Assert.AreEqual(3, queue.Count);
}
[TestMethod]
public async Task Cancellation()
{
var queue = new AsyncQueue<int>();
bool success;
using (var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(3)))
{
success = (await queue.TryDequeueAsync(cancellationTokenSource.Token)).IsSuccess;
}
Assert.AreEqual(false, success);
}
[TestMethod]
public async Task Process_Async()
{
var queue = new AsyncQueue<int>();
var sum = 0;
var worker = Task.Run(async () =>
{
while (sum < 6)
{
sum += (await queue.TryDequeueAsync(CancellationToken.None)).Item;
}
});
queue.Enqueue(1);
await Task.Delay(500);
queue.Enqueue(2);
await Task.Delay(500);
queue.Enqueue(3);
await Task.Delay(500);
Assert.AreEqual(6, sum);
Assert.AreEqual(TaskStatus.RanToCompletion, worker.Status);
}
[TestMethod]
public async Task Process_Async_With_Initial_Delay()
{
var queue = new AsyncQueue<int>();
var sum = 0;
var worker = Task.Run(async () =>
{
while (sum < 6)
{
sum += (await queue.TryDequeueAsync(CancellationToken.None)).Item;
}
});
// This line is the diff to test _Process_Async_
await Task.Delay(500);
queue.Enqueue(1);
await Task.Delay(500);
queue.Enqueue(2);
await Task.Delay(500);
queue.Enqueue(3);
await Task.Delay(500);
Assert.AreEqual(6, sum);
Assert.AreEqual(TaskStatus.RanToCompletion, worker.Status);
}
[TestMethod]
public void Dequeue_Sync()
{
var queue = new AsyncQueue<string>();
queue.Enqueue("1");
queue.Enqueue("2");
queue.Enqueue("3");
Assert.AreEqual("1", queue.TryDequeue().Item);
Assert.AreEqual("2", queue.TryDequeue().Item);
Assert.AreEqual("3", queue.TryDequeue().Item);
}
[TestMethod]
public void Clear()
{
var queue = new AsyncQueue<string>();
queue.Enqueue("1");
queue.Enqueue("2");
queue.Enqueue("3");
queue.Clear();
Assert.AreEqual(0, queue.Count);
queue.Enqueue("4");
Assert.AreEqual(1, queue.Count);
Assert.AreEqual("4", queue.TryDequeue().Item);
}
}
}
@@ -0,0 +1,125 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Internal;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace MQTTnet.Tests
{
[TestClass]
public class BlockingQueue_Tests
{
[TestMethod]
public void Preserve_Order()
{
var queue = new BlockingQueue<string>();
queue.Enqueue("a");
queue.Enqueue("b");
queue.Enqueue("c");
Assert.AreEqual(3, queue.Count);
Assert.AreEqual("a", queue.Dequeue());
Assert.AreEqual("b", queue.Dequeue());
Assert.AreEqual("c", queue.Dequeue());
}
[TestMethod]
public void Remove_First_Items()
{
var queue = new BlockingQueue<string>();
queue.Enqueue("a");
queue.Enqueue("b");
queue.Enqueue("c");
Assert.AreEqual("a", queue.RemoveFirst());
Assert.AreEqual("b", queue.RemoveFirst());
Assert.AreEqual(1, queue.Count);
Assert.AreEqual("c", queue.Dequeue());
}
[TestMethod]
public void Clear_Items()
{
var queue = new BlockingQueue<string>();
queue.Enqueue("a");
queue.Enqueue("b");
queue.Enqueue("c");
Assert.AreEqual(3, queue.Count);
queue.Clear();
Assert.AreEqual(0, queue.Count);
}
[TestMethod]
public async Task Wait_For_Item()
{
var queue = new BlockingQueue<string>();
string item = null;
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
Task.Run(() =>
{
item = queue.Dequeue();
});
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
await Task.Delay(100);
Assert.AreEqual(0, queue.Count);
Assert.AreEqual(null, item);
queue.Enqueue("x");
await Task.Delay(100);
Assert.AreEqual("x", item);
Assert.AreEqual(0, queue.Count);
}
[TestMethod]
public void Wait_For_Items()
{
var number = 0;
var queue = new BlockingQueue<int>();
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
Task.Run(async () =>
{
while (true)
{
queue.Enqueue(1);
await Task.Delay(100);
}
});
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
while (number < 50)
{
queue.Dequeue();
Interlocked.Increment(ref number);
}
}
[TestMethod]
[ExpectedException(typeof(OperationCanceledException))]
public void Use_Disposed_Queue()
{
var queue = new BlockingQueue<int>();
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
Task.Run(() =>
{
Thread.Sleep(1000);
queue.Dispose();
});
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
queue.Dequeue(new CancellationTokenSource(TimeSpan.FromSeconds(2)).Token);
}
}
}
@@ -0,0 +1,75 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Implementations;
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace MQTTnet.Tests
{
[TestClass]
public class CrossPlatformSocket_Tests
{
[TestMethod]
public async Task Connect_Send_Receive()
{
var crossPlatformSocket = new CrossPlatformSocket();
await crossPlatformSocket.ConnectAsync("www.google.de", 80, CancellationToken.None);
var requestBuffer = Encoding.UTF8.GetBytes("GET / HTTP/1.1\r\nHost: www.google.de\r\n\r\n");
await crossPlatformSocket.SendAsync(new ArraySegment<byte>(requestBuffer), System.Net.Sockets.SocketFlags.None);
var buffer = new byte[1024];
var length = await crossPlatformSocket.ReceiveAsync(new ArraySegment<byte>(buffer), System.Net.Sockets.SocketFlags.None);
crossPlatformSocket.Dispose();
var responseText = Encoding.UTF8.GetString(buffer, 0, length);
Assert.IsTrue(responseText.Contains("HTTP/1.1 200 OK"));
}
[TestMethod]
[ExpectedException(typeof(OperationCanceledException))]
public async Task Try_Connect_Invalid_Host()
{
var crossPlatformSocket = new CrossPlatformSocket();
var cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(5));
cancellationToken.Token.Register(() => crossPlatformSocket.Dispose());
await crossPlatformSocket.ConnectAsync("www.google.de", 54321, cancellationToken.Token);
}
//[TestMethod]
//public async Task Use_Disconnected_Socket()
//{
// var crossPlatformSocket = new CrossPlatformSocket();
// await crossPlatformSocket.ConnectAsync("www.google.de", 80);
// var requestBuffer = Encoding.UTF8.GetBytes("GET /wrong_uri HTTP/1.1\r\nConnection: close\r\n\r\n");
// await crossPlatformSocket.SendAsync(new ArraySegment<byte>(requestBuffer), System.Net.Sockets.SocketFlags.None);
// var buffer = new byte[64000];
// var length = await crossPlatformSocket.ReceiveAsync(new ArraySegment<byte>(buffer), System.Net.Sockets.SocketFlags.None);
// await Task.Delay(500);
// await crossPlatformSocket.SendAsync(new ArraySegment<byte>(requestBuffer), System.Net.Sockets.SocketFlags.None);
//}
[TestMethod]
public void Set_Options()
{
var crossPlatformSocket = new CrossPlatformSocket();
Assert.IsFalse(crossPlatformSocket.ReuseAddress);
crossPlatformSocket.ReuseAddress = true;
Assert.IsTrue(crossPlatformSocket.ReuseAddress);
Assert.IsFalse(crossPlatformSocket.NoDelay);
crossPlatformSocket.NoDelay = true;
Assert.IsTrue(crossPlatformSocket.NoDelay);
}
}
}
@@ -0,0 +1,110 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Internal;
using MQTTnet.Packets;
namespace MQTTnet.Tests.Internal
{
[TestClass]
public sealed class MqttPacketBus_Tests
{
[TestMethod]
[ExpectedException(typeof(OperationCanceledException))]
public async Task Wait_With_Empty_Bus()
{
var bus = new MqttPacketBus();
using (var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(1)))
{
await bus.DequeueAsync(timeout.Token);
}
}
[TestMethod]
public void Alternate_Priorities()
{
var bus = new MqttPacketBus();
bus.Enqueue(new MqttPacketBusItem(new MqttPublishPacket()), MqttPacketBusPartition.Data);
bus.Enqueue(new MqttPacketBusItem(new MqttPublishPacket()), MqttPacketBusPartition.Data);
bus.Enqueue(new MqttPacketBusItem(new MqttPublishPacket()), MqttPacketBusPartition.Data);
bus.Enqueue(new MqttPacketBusItem(new MqttSubAckPacket()), MqttPacketBusPartition.Control);
bus.Enqueue(new MqttPacketBusItem(new MqttSubAckPacket()), MqttPacketBusPartition.Control);
bus.Enqueue(new MqttPacketBusItem(new MqttSubAckPacket()), MqttPacketBusPartition.Control);
bus.Enqueue(new MqttPacketBusItem(new MqttPingRespPacket()), MqttPacketBusPartition.Health);
bus.Enqueue(new MqttPacketBusItem(new MqttPingRespPacket()), MqttPacketBusPartition.Health);
bus.Enqueue(new MqttPacketBusItem(new MqttPingRespPacket()), MqttPacketBusPartition.Health);
Assert.AreEqual(9, bus.PacketsCount);
Assert.IsInstanceOfType(bus.DequeueAsync(CancellationToken.None).Result.Packet, typeof(MqttPublishPacket));
Assert.IsInstanceOfType(bus.DequeueAsync(CancellationToken.None).Result.Packet, typeof(MqttSubAckPacket));
Assert.IsInstanceOfType(bus.DequeueAsync(CancellationToken.None).Result.Packet, typeof(MqttPingRespPacket));
Assert.IsInstanceOfType(bus.DequeueAsync(CancellationToken.None).Result.Packet, typeof(MqttPublishPacket));
Assert.IsInstanceOfType(bus.DequeueAsync(CancellationToken.None).Result.Packet, typeof(MqttSubAckPacket));
Assert.IsInstanceOfType(bus.DequeueAsync(CancellationToken.None).Result.Packet, typeof(MqttPingRespPacket));
Assert.IsInstanceOfType(bus.DequeueAsync(CancellationToken.None).Result.Packet, typeof(MqttPublishPacket));
Assert.IsInstanceOfType(bus.DequeueAsync(CancellationToken.None).Result.Packet, typeof(MqttSubAckPacket));
Assert.IsInstanceOfType(bus.DequeueAsync(CancellationToken.None).Result.Packet, typeof(MqttPingRespPacket));
Assert.AreEqual(0, bus.PacketsCount);
}
[TestMethod]
public void Export_Packets_Without_Dequeue()
{
var bus = new MqttPacketBus();
bus.Enqueue(new MqttPacketBusItem(new MqttPublishPacket()), MqttPacketBusPartition.Data);
bus.Enqueue(new MqttPacketBusItem(new MqttPublishPacket()), MqttPacketBusPartition.Data);
bus.Enqueue(new MqttPacketBusItem(new MqttPublishPacket()), MqttPacketBusPartition.Data);
Assert.AreEqual(3, bus.PacketsCount);
var exportedPackets = bus.ExportPackets(MqttPacketBusPartition.Control);
Assert.AreEqual(0, exportedPackets.Count);
exportedPackets = bus.ExportPackets(MqttPacketBusPartition.Health);
Assert.AreEqual(0, exportedPackets.Count);
exportedPackets = bus.ExportPackets(MqttPacketBusPartition.Data);
Assert.AreEqual(3, exportedPackets.Count);
Assert.AreEqual(3, bus.PacketsCount);
}
[TestMethod]
public void Await_Single_Packet()
{
var bus = new MqttPacketBus();
var delivered = false;
bus.Enqueue(new MqttPublishPacket(), MqttPacketBusPartition.Data);
bus.Enqueue(new MqttPublishPacket(), MqttPacketBusPartition.Data);
bus.Enqueue(new MqttPublishPacket(), MqttPacketBusPartition.Data).Delivered += (_, __) =>
{
delivered = true;
};
Assert.IsFalse(delivered);
bus.DequeueAsync(CancellationToken.None).Result.MarkAsDelivered();
Assert.IsFalse(delivered);
bus.DequeueAsync(CancellationToken.None).Result.MarkAsDelivered();
Assert.IsFalse(delivered);
bus.DequeueAsync(CancellationToken.None).Result.MarkAsDelivered();
// The third packet has the event attached.
Assert.IsTrue(delivered);
}
}
}