Use latest language features (#2176)

* Make use of language features line AsyncDispose, init etc.

* Fix build errors

* Improve Unit Tests

* Improve Unit Tests

* Improve Unit Tests

* Update samples

* Remove obsolete benchmarks

* Code cleanup

* Improve unit tests

* Improve Unit Tests

* Fix Unit Tests

* Improve Unit Tests

* Improve Unit Tests

* Restore unit tests

* Exclude load tests from unit tests
This commit is contained in:
Christian
2025-08-30 10:52:59 +02:00
committed by GitHub
parent 247988e633
commit e43e7f8e36
330 changed files with 21417 additions and 22919 deletions
+117 -117
View File
@@ -8,133 +8,133 @@ using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Internal;
namespace MQTTnet.Tests.Internal
namespace MQTTnet.Tests.Internal;
// ReSharper disable InconsistentNaming
[TestClass]
public sealed class AsyncEvent_Tests
{
[TestClass]
public sealed class AsyncEvent_Tests
int _testEventAsyncCount;
[TestMethod]
public async Task Attach_and_Detach_Sync_And_Async_EventHandler()
{
int _testEventAsyncCount;
var testClass = new TestClass();
[TestMethod]
public async Task Attach_and_Detach_Sync_And_Async_EventHandler()
testClass.TestEventAsync += OnTestEventAsync;
testClass.TestEvent += OnTestEvent;
await testClass.FireEventAsync(EventArgs.Empty);
Assert.AreEqual(2, _testEventAsyncCount);
testClass.TestEvent -= OnTestEvent;
await testClass.FireEventAsync(EventArgs.Empty);
Assert.AreEqual(3, _testEventAsyncCount);
testClass.TestEventAsync -= OnTestEventAsync;
await testClass.FireEventAsync(EventArgs.Empty);
Assert.AreEqual(3, _testEventAsyncCount);
}
[TestMethod]
public async Task Attach_EventHandler()
{
var testClass = new TestClass();
testClass.TestEventAsync += OnTestEventAsync;
await testClass.FireEventAsync(EventArgs.Empty);
Assert.AreEqual(1, _testEventAsyncCount);
}
[TestMethod]
public async Task Attach_Sync_And_Async_EventHandler()
{
var testClass = new TestClass();
testClass.TestEventAsync += OnTestEventAsync;
testClass.TestEvent += OnTestEvent;
await testClass.FireEventAsync(EventArgs.Empty);
Assert.AreEqual(2, _testEventAsyncCount);
}
[TestMethod]
public async Task Detach_EventHandler()
{
var testClass = new TestClass();
testClass.TestEventAsync += OnTestEventAsync;
testClass.TestEventAsync -= OnTestEventAsync;
await testClass.FireEventAsync(EventArgs.Empty);
Assert.AreEqual(0, _testEventAsyncCount);
}
[TestMethod]
public void Has_Handlers()
{
var testClass = new TestClass();
testClass.TestEventAsync += OnTestEventAsync;
Assert.AreEqual(true, testClass.HasTestHandlers);
}
[TestMethod]
public void No_Handlers()
{
var testClass = new TestClass();
Assert.AreEqual(false, testClass.HasTestHandlers);
}
[TestMethod]
public void Remove_Handlers()
{
var testClass = new TestClass();
testClass.TestEventAsync += OnTestEventAsync;
testClass.TestEventAsync -= OnTestEventAsync;
Assert.AreEqual(false, testClass.HasTestHandlers);
}
void OnTestEvent(EventArgs arg)
{
Interlocked.Increment(ref _testEventAsyncCount);
}
Task OnTestEventAsync(EventArgs arg)
{
Interlocked.Increment(ref _testEventAsyncCount);
return CompletedTask.Instance;
}
sealed class TestClass
{
readonly AsyncEvent<EventArgs> _testEvent = new();
public event Action<EventArgs> TestEvent
{
var testClass = new TestClass();
testClass.TestEventAsync += OnTestEventAsync;
testClass.TestEvent += OnTestEvent;
await testClass.FireEventAsync(EventArgs.Empty);
Assert.AreEqual(2, _testEventAsyncCount);
testClass.TestEvent -= OnTestEvent;
await testClass.FireEventAsync(EventArgs.Empty);
Assert.AreEqual(3, _testEventAsyncCount);
testClass.TestEventAsync -= OnTestEventAsync;
await testClass.FireEventAsync(EventArgs.Empty);
Assert.AreEqual(3, _testEventAsyncCount);
add => _testEvent.AddHandler(value);
remove => _testEvent.RemoveHandler(value);
}
[TestMethod]
public async Task Attach_EventHandler()
public event Func<EventArgs, Task> TestEventAsync
{
var testClass = new TestClass();
testClass.TestEventAsync += OnTestEventAsync;
await testClass.FireEventAsync(EventArgs.Empty);
Assert.AreEqual(1, _testEventAsyncCount);
add => _testEvent.AddHandler(value);
remove => _testEvent.RemoveHandler(value);
}
[TestMethod]
public async Task Attach_Sync_And_Async_EventHandler()
public bool HasTestHandlers => _testEvent.HasHandlers;
public Task FireEventAsync(EventArgs eventArgs)
{
var testClass = new TestClass();
testClass.TestEventAsync += OnTestEventAsync;
testClass.TestEvent += OnTestEvent;
await testClass.FireEventAsync(EventArgs.Empty);
Assert.AreEqual(2, _testEventAsyncCount);
}
[TestMethod]
public async Task Detach_EventHandler()
{
var testClass = new TestClass();
testClass.TestEventAsync += OnTestEventAsync;
testClass.TestEventAsync -= OnTestEventAsync;
await testClass.FireEventAsync(EventArgs.Empty);
Assert.AreEqual(0, _testEventAsyncCount);
}
[TestMethod]
public void Has_Handlers()
{
var testClass = new TestClass();
testClass.TestEventAsync += OnTestEventAsync;
Assert.AreEqual(true, testClass.HasTestHandlers);
}
[TestMethod]
public void No_Handlers()
{
var testClass = new TestClass();
Assert.AreEqual(false, testClass.HasTestHandlers);
}
[TestMethod]
public void Remove_Handlers()
{
var testClass = new TestClass();
testClass.TestEventAsync += OnTestEventAsync;
testClass.TestEventAsync -= OnTestEventAsync;
Assert.AreEqual(false, testClass.HasTestHandlers);
}
void OnTestEvent(EventArgs arg)
{
Interlocked.Increment(ref _testEventAsyncCount);
}
Task OnTestEventAsync(EventArgs arg)
{
Interlocked.Increment(ref _testEventAsyncCount);
return CompletedTask.Instance;
}
sealed class TestClass
{
readonly AsyncEvent<EventArgs> _testEvent = new AsyncEvent<EventArgs>();
public event Action<EventArgs> TestEvent
{
add => _testEvent.AddHandler(value);
remove => _testEvent.RemoveHandler(value);
}
public event Func<EventArgs, Task> TestEventAsync
{
add => _testEvent.AddHandler(value);
remove => _testEvent.RemoveHandler(value);
}
public bool HasTestHandlers => _testEvent.HasHandlers;
public Task FireEventAsync(EventArgs eventArgs)
{
return _testEvent.InvokeAsync(eventArgs);
}
return _testEvent.InvokeAsync(eventArgs);
}
}
}
+231 -247
View File
@@ -9,283 +9,267 @@ using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Internal;
namespace MQTTnet.Tests.Internal
namespace MQTTnet.Tests.Internal;
// ReSharper disable InconsistentNaming
[TestClass]
public sealed class AsyncLock_Tests
{
[TestClass]
public sealed class AsyncLock_Tests
[TestMethod]
public async Task Cancellation_Of_Awaiter()
{
[TestMethod]
public async Task Cancellation_Of_Awaiter()
var @lock = new AsyncLock();
// This call will not yet "release" the lock due to missing _using_.
var releaser = await @lock.EnterAsync().ConfigureAwait(false);
var counter = 0;
Debug.WriteLine("Prepared locked lock.");
_ = Task.Run(
async () =>
{
// SHOULD GET TIMEOUT!
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(1));
using (await @lock.EnterAsync(timeout.Token))
{
Debug.WriteLine("Task 1 incremented");
counter++;
}
});
_ = Task.Run(
async () =>
{
// SHOULD GET TIMEOUT!
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(2));
using (await @lock.EnterAsync(timeout.Token))
{
Debug.WriteLine("Task 2 incremented");
counter++;
}
});
_ = Task.Run(
async () =>
{
// SHOULD GET TIMEOUT!
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(3));
using (await @lock.EnterAsync(timeout.Token))
{
Debug.WriteLine("Task 3 incremented");
counter++;
}
});
_ = Task.Run(
async () =>
{
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(4));
using (await @lock.EnterAsync(timeout.Token))
{
Debug.WriteLine("Task 4 incremented");
counter++;
}
});
_ = Task.Run(
async () =>
{
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5));
using (await @lock.EnterAsync(timeout.Token))
{
Debug.WriteLine("Task 5 incremented");
counter++;
}
});
_ = Task.Run(
async () =>
{
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(6));
using (await @lock.EnterAsync(timeout.Token))
{
Debug.WriteLine("Task 6 incremented");
counter++;
}
});
Debug.WriteLine("Delay before release...");
await Task.Delay(TimeSpan.FromSeconds(3.1));
releaser.Dispose();
Debug.WriteLine("Wait for all tasks...");
await Task.Delay(TimeSpan.FromSeconds(6.1));
Assert.AreEqual(3, counter);
}
[TestMethod]
public void Lock_Parallel_Tasks()
{
const int taskCount = 50;
var @lock = new AsyncLock();
var tasks = new Task[taskCount];
var globalI = 0;
for (var i = 0; i < taskCount; i++)
{
var @lock = new AsyncLock();
// This call will not yet "release" the lock due to missing _using_.
var releaser = await @lock.EnterAsync().ConfigureAwait(false);
var counter = 0;
Debug.WriteLine("Prepared locked lock.");
_ = Task.Run(
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
tasks[i] = Task.Run(
async () =>
{
// SHOULD GET TIMEOUT!
using (var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(1)))
using (await @lock.EnterAsync())
{
using (await @lock.EnterAsync(timeout.Token))
{
Debug.WriteLine("Task 1 incremented");
counter++;
}
var localI = globalI;
await Task.Delay(5); // Increase the chance for wrong data.
localI++;
globalI = localI;
}
});
_ = Task.Run(
async () =>
{
// SHOULD GET TIMEOUT!
using (var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(2)))
{
using (await @lock.EnterAsync(timeout.Token))
{
Debug.WriteLine("Task 2 incremented");
counter++;
}
}
});
_ = Task.Run(
async () =>
{
// SHOULD GET TIMEOUT!
using (var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(3)))
{
using (await @lock.EnterAsync(timeout.Token))
{
Debug.WriteLine("Task 3 incremented");
counter++;
}
}
});
_ = Task.Run(
async () =>
{
using (var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(4)))
{
using (await @lock.EnterAsync(timeout.Token))
{
Debug.WriteLine("Task 4 incremented");
counter++;
}
}
});
_ = Task.Run(
async () =>
{
using (var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5)))
{
using (await @lock.EnterAsync(timeout.Token))
{
Debug.WriteLine("Task 5 incremented");
counter++;
}
}
});
_ = Task.Run(
async () =>
{
using (var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(6)))
{
using (await @lock.EnterAsync(timeout.Token))
{
Debug.WriteLine("Task 6 incremented");
counter++;
}
}
});
Debug.WriteLine("Delay before release...");
await Task.Delay(TimeSpan.FromSeconds(3.1));
releaser.Dispose();
Debug.WriteLine("Wait for all tasks...");
await Task.Delay(TimeSpan.FromSeconds(6.1));
Assert.AreEqual(3, counter);
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
}
[TestMethod]
public void Lock_Parallel_Tasks()
Task.WaitAll(tasks);
Assert.AreEqual(taskCount, globalI);
}
[TestMethod]
public void Lock_10_Parallel_Tasks_With_Dispose_Doesnt_Lockup()
{
const int ThreadsCount = 10;
var threads = new Task[ThreadsCount];
var @lock = new AsyncLock();
var globalI = 0;
for (var i = 0; i < ThreadsCount; i++)
{
const int taskCount = 50;
var @lock = new AsyncLock();
var tasks = new Task[taskCount];
var globalI = 0;
for (var i = 0; i < taskCount; i++)
{
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
tasks[i] = Task.Run(
threads[i] = Task.Run(
async () =>
{
using (await @lock.EnterAsync())
{
var localI = globalI;
await Task.Delay(5); // Increase the chance for wrong data.
await Task.Delay(10); // Increase the chance for wrong data.
localI++;
globalI = localI;
}
})
.ContinueWith(
x =>
{
if (globalI == 5)
{
@lock.Dispose();
@lock = new AsyncLock();
}
if (x.Exception != null)
{
Debug.WriteLine(x.Exception.GetBaseException().GetType().Name);
}
});
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
}
Task.WaitAll(tasks);
Assert.AreEqual(taskCount, globalI);
}
[TestMethod]
public void Lock_10_Parallel_Tasks_With_Dispose_Doesnt_Lockup()
Task.WaitAll(threads);
// Expect only 6 because the others are failing due to disposal (if (globalI == 5)).
Assert.AreEqual(6, globalI);
}
[TestMethod]
public async Task Lock_Serial_Calls()
{
var sum = 0;
var @lock = new AsyncLock();
for (var i = 0; i < 100; i++)
{
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 (await @lock.EnterAsync())
{
var localI = globalI;
await Task.Delay(10); // Increase the chance for wrong data.
localI++;
globalI = localI;
}
})
.ContinueWith(
x =>
{
if (globalI == 5)
{
@lock.Dispose();
@lock = new AsyncLock();
}
if (x.Exception != null)
{
Debug.WriteLine(x.Exception.GetBaseException().GetType().Name);
}
});
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
}
Task.WaitAll(threads);
// Expect only 6 because the others are failing due to disposal (if (globalI == 5)).
Assert.AreEqual(6, globalI);
}
[TestMethod]
public async Task Lock_Serial_Calls()
{
var sum = 0;
var @lock = new AsyncLock();
for (var i = 0; i < 100; i++)
{
using (await @lock.EnterAsync().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.EnterAsync().ConfigureAwait(false);
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(3)))
{
await @lock.EnterAsync(cts.Token).ConfigureAwait(false);
}
}
[TestMethod]
public async Task Test_Cancellation_With_Later_Access()
{
var asyncLock = new AsyncLock();
var releaser = await asyncLock.EnterAsync().ConfigureAwait(false);
try
{
using (var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(3)))
{
await asyncLock.EnterAsync(timeout.Token).ConfigureAwait(false);
}
Assert.Fail("Exception should be thrown!");
}
catch (OperationCanceledException)
{
}
releaser.Dispose();
using (await asyncLock.EnterAsync(CancellationToken.None).ConfigureAwait(false))
{
// When the method finished, the thread got access.
}
}
[TestMethod]
public async Task Use_After_Cancellation()
{
var @lock = new AsyncLock();
// This call will not yet "release" the lock due to missing _using_.
var releaser = await @lock.EnterAsync().ConfigureAwait(false);
try
{
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(3)))
{
await @lock.EnterAsync(cts.Token).ConfigureAwait(false);
}
}
catch (OperationCanceledException)
{
// Expected exception!
}
releaser.Dispose();
// Regular usage after cancellation.
using (await @lock.EnterAsync().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.EnterAsync().ConfigureAwait(false);
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(3));
await @lock.EnterAsync(cts.Token).ConfigureAwait(false);
}
[TestMethod]
public async Task Test_Cancellation_With_Later_Access()
{
var asyncLock = new AsyncLock();
var releaser = await asyncLock.EnterAsync().ConfigureAwait(false);
try
{
using (var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(3)))
{
await asyncLock.EnterAsync(timeout.Token).ConfigureAwait(false);
}
using (await @lock.EnterAsync().ConfigureAwait(false))
{
}
Assert.Fail("Exception should be thrown!");
}
catch (OperationCanceledException)
{
}
using (await @lock.EnterAsync().ConfigureAwait(false))
{
}
releaser.Dispose();
using (await asyncLock.EnterAsync(CancellationToken.None).ConfigureAwait(false))
{
// When the method finished, the thread got access.
}
}
[TestMethod]
public async Task Use_After_Cancellation()
{
var @lock = new AsyncLock();
// This call will not yet "release" the lock due to missing _using_.
var releaser = await @lock.EnterAsync().ConfigureAwait(false);
try
{
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(3));
await @lock.EnterAsync(cts.Token).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
// Expected exception!
}
releaser.Dispose();
// Regular usage after cancellation.
using (await @lock.EnterAsync().ConfigureAwait(false))
{
}
using (await @lock.EnterAsync().ConfigureAwait(false))
{
}
using (await @lock.EnterAsync().ConfigureAwait(false))
{
}
}
}
+131 -131
View File
@@ -8,138 +8,138 @@ using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Internal;
namespace MQTTnet.Tests.Internal
namespace MQTTnet.Tests.Internal;
// ReSharper disable InconsistentNaming
[TestClass]
public class AsyncQueue_Tests
{
[TestClass]
public class AsyncQueue_Tests
[TestMethod]
public async Task Preserve_Order()
{
[TestMethod]
public async Task Preserve_Order()
{
var queue = new AsyncQueue<string>();
queue.Enqueue("1");
queue.Enqueue("2");
queue.Enqueue("3");
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);
}
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);
}
}
@@ -9,120 +9,114 @@ using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Internal;
namespace MQTTnet.Tests.Internal
namespace MQTTnet.Tests.Internal;
// ReSharper disable InconsistentNaming
[TestClass]
public sealed class AsyncSignal_Tests
{
[TestClass]
public sealed class AsyncSignal_Tests
[TestMethod]
[ExpectedException(typeof(TaskCanceledException))]
public async Task Cancel_If_No_Signal()
{
[TestMethod]
[ExpectedException(typeof(TaskCanceledException))]
public async Task Cancel_If_No_Signal()
{
var asyncSignal = new AsyncSignal();
var asyncSignal = new AsyncSignal();
using (var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(2)))
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(2));
await asyncSignal.WaitAsync(timeout.Token);
Assert.Fail("There is no signal. So we must fail here!");
}
[TestMethod]
[ExpectedException(typeof(ObjectDisposedException))]
public async Task Dispose_Properly()
{
var asyncSignal = new AsyncSignal();
// The timeout will not be reached but another task will kill the async signal.
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(999));
_ = Task.Run(
async () =>
{
await asyncSignal.WaitAsync(timeout.Token);
await Task.Delay(2000, CancellationToken.None);
asyncSignal.Dispose();
},
CancellationToken.None);
Assert.Fail("There is no signal. So we must fail here!");
}
}
await asyncSignal.WaitAsync(timeout.Token);
[TestMethod]
[ExpectedException(typeof(ObjectDisposedException))]
public async Task Dispose_Properly()
Assert.Fail("There is no signal. So we must fail here!");
}
[TestMethod]
public async Task Reset_Signal()
{
var asyncSignal = new AsyncSignal();
// WaitAsync should fail because no signal is available.
for (var i = 0; i < 10; i++)
{
var asyncSignal = new AsyncSignal();
// The timeout will not be reached but another task will kill the async signal.
using (var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(999)))
try
{
_ = Task.Run(
async () =>
{
await Task.Delay(2000, CancellationToken.None);
asyncSignal.Dispose();
},
CancellationToken.None);
await asyncSignal.WaitAsync(timeout.Token);
Assert.Fail("There is no signal. So we must fail here!");
}
}
[TestMethod]
public async Task Reset_Signal()
{
var asyncSignal = new AsyncSignal();
// WaitAsync should fail because no signal is available.
for (var i = 0; i < 10; i++)
{
try
using (var timeout = new CancellationTokenSource(TimeSpan.FromMilliseconds(100)))
{
using (var timeout = new CancellationTokenSource(TimeSpan.FromMilliseconds(100)))
{
await asyncSignal.WaitAsync(timeout.Token);
}
Assert.Fail("This must fail because the signal is not yet set.");
await asyncSignal.WaitAsync(timeout.Token);
}
catch (OperationCanceledException)
{
}
asyncSignal.Set();
// WaitAsync should return directly because the signal is available.
await asyncSignal.WaitAsync();
Assert.Fail("This must fail because the signal is not yet set.");
}
}
[TestMethod]
public async Task Signal()
{
var asyncSignal = new AsyncSignal();
// The timeout will not be reached but another task will kill the async signal.
using (var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(3)))
catch (OperationCanceledException)
{
var stopwatch = Stopwatch.StartNew();
_ = Task.Run(
async () =>
{
await Task.Delay(1000, CancellationToken.None);
asyncSignal.Set();
},
CancellationToken.None);
await asyncSignal.WaitAsync(timeout.Token);
stopwatch.Stop();
Assert.IsTrue(stopwatch.ElapsedMilliseconds > 900);
}
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public async Task Fail_For_Two_Waiters()
{
var asyncSignal = new AsyncSignal();
asyncSignal.Set();
// This thread will wait properly because it is the first waiter.
_ = Task.Run(
async () =>
{
await asyncSignal.WaitAsync();
},
CancellationToken.None);
await Task.Delay(1000);
// Now the current thread must fail because there is already a waiter.
// WaitAsync should return directly because the signal is available.
await asyncSignal.WaitAsync();
}
}
[TestMethod]
public async Task Signal()
{
var asyncSignal = new AsyncSignal();
// The timeout will not be reached but another task will kill the async signal.
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(3));
var stopwatch = Stopwatch.StartNew();
_ = Task.Run(
async () =>
{
await Task.Delay(1000, CancellationToken.None);
asyncSignal.Set();
},
CancellationToken.None);
await asyncSignal.WaitAsync(timeout.Token);
stopwatch.Stop();
Assert.IsTrue(stopwatch.ElapsedMilliseconds > 900);
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public async Task Fail_For_Two_Waiters()
{
var asyncSignal = new AsyncSignal();
// This thread will wait properly because it is the first waiter.
_ = Task.Run(
async () =>
{
await asyncSignal.WaitAsync().ConfigureAwait(false);
},
CancellationToken.None);
await Task.Delay(1000);
// Now the current thread must fail because there is already a waiter.
await asyncSignal.WaitAsync().ConfigureAwait(false);
}
}
@@ -8,122 +8,122 @@ using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Internal;
namespace MQTTnet.Tests.Internal
namespace MQTTnet.Tests.Internal;
// ReSharper disable InconsistentNaming
[TestClass]
public class BlockingQueue_Tests
{
[TestClass]
public class BlockingQueue_Tests
[TestMethod]
public void Preserve_Order()
{
[TestMethod]
public void Preserve_Order()
{
var queue = new BlockingQueue<string>();
queue.Enqueue("a");
queue.Enqueue("b");
queue.Enqueue("c");
var queue = new BlockingQueue<string>();
queue.Enqueue("a");
queue.Enqueue("b");
queue.Enqueue("c");
Assert.AreEqual(3, queue.Count);
Assert.AreEqual(3, queue.Count);
Assert.AreEqual("a", queue.Dequeue());
Assert.AreEqual("b", queue.Dequeue());
Assert.AreEqual("c", queue.Dequeue());
}
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");
[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("a", queue.RemoveFirst());
Assert.AreEqual("b", queue.RemoveFirst());
Assert.AreEqual(1, queue.Count);
Assert.AreEqual(1, queue.Count);
Assert.AreEqual("c", queue.Dequeue());
}
Assert.AreEqual("c", queue.Dequeue());
}
[TestMethod]
public void Clear_Items()
{
var queue = new BlockingQueue<string>();
queue.Enqueue("a");
queue.Enqueue("b");
queue.Enqueue("c");
[TestMethod]
public void Clear_Items()
{
var queue = new BlockingQueue<string>();
queue.Enqueue("a");
queue.Enqueue("b");
queue.Enqueue("c");
Assert.AreEqual(3, queue.Count);
Assert.AreEqual(3, queue.Count);
queue.Clear();
queue.Clear();
Assert.AreEqual(0, queue.Count);
}
Assert.AreEqual(0, queue.Count);
}
[TestMethod]
public async Task Wait_For_Item()
{
var queue = new BlockingQueue<string>();
[TestMethod]
public async Task Wait_For_Item()
{
var queue = new BlockingQueue<string>();
string item = null;
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();
});
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);
await Task.Delay(100);
Assert.AreEqual(0, queue.Count);
Assert.AreEqual(null, item);
Assert.AreEqual(0, queue.Count);
Assert.AreEqual(null, item);
queue.Enqueue("x");
queue.Enqueue("x");
await Task.Delay(100);
await Task.Delay(100);
Assert.AreEqual("x", item);
Assert.AreEqual(0, queue.Count);
}
Assert.AreEqual("x", item);
Assert.AreEqual(0, queue.Count);
}
[TestMethod]
public void Wait_For_Items()
{
var number = 0;
[TestMethod]
public void Wait_For_Items()
{
var number = 0;
var queue = new BlockingQueue<int>();
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 () =>
Task.Run(async () =>
{
while (true)
{
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);
queue.Enqueue(1);
await Task.Delay(100);
}
}
[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);
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);
}
}
@@ -11,71 +11,71 @@ using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Implementations;
namespace MQTTnet.Tests.Internal
namespace MQTTnet.Tests.Internal;
// ReSharper disable InconsistentNaming
[TestClass]
public class CrossPlatformSocket_Tests
{
[TestClass]
public class CrossPlatformSocket_Tests
[TestMethod]
public async Task Connect_Send_Receive()
{
[TestMethod]
public async Task Connect_Send_Receive()
{
var crossPlatformSocket = new CrossPlatformSocket(ProtocolType.Tcp);
await crossPlatformSocket.ConnectAsync(new DnsEndPoint("www.google.de", 80), CancellationToken.None);
var crossPlatformSocket = new CrossPlatformSocket(ProtocolType.Tcp);
await crossPlatformSocket.ConnectAsync(new DnsEndPoint("www.github.com", 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 requestBuffer = "GET / HTTP/1.1\r\nHost: www.github.com\r\n\r\n"u8.ToArray();
await crossPlatformSocket.SendAsync(new ArraySegment<byte>(requestBuffer), SocketFlags.None);
var buffer = new byte[1024];
var length = await crossPlatformSocket.ReceiveAsync(new ArraySegment<byte>(buffer), System.Net.Sockets.SocketFlags.None);
crossPlatformSocket.Dispose();
var buffer = new byte[1024];
var length = await crossPlatformSocket.ReceiveAsync(new ArraySegment<byte>(buffer), SocketFlags.None);
crossPlatformSocket.Dispose();
var responseText = Encoding.UTF8.GetString(buffer, 0, length);
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(ProtocolType.Tcp);
var cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(5));
cancellationToken.Token.Register(() => crossPlatformSocket.Dispose());
await crossPlatformSocket.ConnectAsync(new DnsEndPoint("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(ProtocolType.Tcp);
Assert.IsFalse(crossPlatformSocket.ReuseAddress);
crossPlatformSocket.ReuseAddress = true;
Assert.IsTrue(crossPlatformSocket.ReuseAddress);
Assert.IsFalse(crossPlatformSocket.NoDelay);
crossPlatformSocket.NoDelay = true;
Assert.IsTrue(crossPlatformSocket.NoDelay);
}
Assert.IsTrue(responseText.Contains("HTTP/1.1"));
}
}
[TestMethod]
[ExpectedException(typeof(OperationCanceledException))]
public async Task Try_Connect_Invalid_Host()
{
var crossPlatformSocket = new CrossPlatformSocket(ProtocolType.Tcp);
var cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(5));
cancellationToken.Token.Register(() => crossPlatformSocket.Dispose());
await crossPlatformSocket.ConnectAsync(new DnsEndPoint("www.github.com", 54321), cancellationToken.Token).ConfigureAwait(false);
}
// [TestMethod]
// public async Task Use_Disconnected_Socket()
// {
// var crossPlatformSocket = new CrossPlatformSocket(ProtocolType.Tcp);
//
// await crossPlatformSocket.ConnectAsync("www.github.com", 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(ProtocolType.Tcp);
Assert.IsFalse(crossPlatformSocket.ReuseAddress);
crossPlatformSocket.ReuseAddress = true;
Assert.IsTrue(crossPlatformSocket.ReuseAddress);
Assert.IsFalse(crossPlatformSocket.NoDelay);
crossPlatformSocket.NoDelay = true;
Assert.IsTrue(crossPlatformSocket.NoDelay);
}
}
@@ -7,37 +7,37 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Internal;
using MQTTnet.Packets;
namespace MQTTnet.Tests.Internal
namespace MQTTnet.Tests.Internal;
// ReSharper disable InconsistentNaming
[TestClass]
public sealed class MqttPacketBusItem_Tests
{
[TestClass]
public sealed class MqttPacketBusItem_Tests
[TestMethod]
public void Fire_Completed_Event()
{
[TestMethod]
public void Fire_Completed_Event()
var eventFired = false;
var item = new MqttPacketBusItem(new MqttPublishPacket());
item.Completed += (_, _) =>
{
var eventFired = false;
eventFired = true;
};
var item = new MqttPacketBusItem(new MqttPublishPacket());
item.Completed += (_, __) =>
{
eventFired = true;
};
item.Complete();
item.Complete();
Assert.IsTrue(eventFired);
}
Assert.IsTrue(eventFired);
}
[TestMethod]
[ExpectedException(typeof(TaskCanceledException))]
public async Task Wait_Packet_Bus_Item_After_Already_Canceled()
{
var item = new MqttPacketBusItem(new MqttPublishPacket());
[TestMethod]
[ExpectedException(typeof(TaskCanceledException))]
public async Task Wait_Packet_Bus_Item_After_Already_Canceled()
{
var item = new MqttPacketBusItem(new MqttPublishPacket());
// Finish the item before the actual
item.Cancel();
// Finish the item before the actual
item.Cancel();
await item.WaitAsync();
}
await item.WaitAsync().ConfigureAwait(false);
}
}
@@ -3,149 +3,146 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Internal;
using MQTTnet.Packets;
namespace MQTTnet.Tests.Internal
namespace MQTTnet.Tests.Internal;
[SuppressMessage("ReSharper", "InconsistentNaming")]
[TestClass]
public sealed class MqttPacketBus_Tests
{
[TestClass]
public sealed class MqttPacketBus_Tests
{
[TestMethod]
public void Alternate_Priorities()
[TestMethod]
public void Alternate_Priorities()
{
var bus = new MqttPacketBus();
bus.EnqueueItem(new MqttPacketBusItem(new MqttPublishPacket()), MqttPacketBusPartition.Data);
bus.EnqueueItem(new MqttPacketBusItem(new MqttPublishPacket()), MqttPacketBusPartition.Data);
bus.EnqueueItem(new MqttPacketBusItem(new MqttPublishPacket()), MqttPacketBusPartition.Data);
bus.EnqueueItem(new MqttPacketBusItem(new MqttSubAckPacket()), MqttPacketBusPartition.Control);
bus.EnqueueItem(new MqttPacketBusItem(new MqttSubAckPacket()), MqttPacketBusPartition.Control);
bus.EnqueueItem(new MqttPacketBusItem(new MqttSubAckPacket()), MqttPacketBusPartition.Control);
bus.EnqueueItem(new MqttPacketBusItem(new MqttPingRespPacket()), MqttPacketBusPartition.Health);
bus.EnqueueItem(new MqttPacketBusItem(new MqttPingRespPacket()), MqttPacketBusPartition.Health);
bus.EnqueueItem(new MqttPacketBusItem(new MqttPingRespPacket()), MqttPacketBusPartition.Health);
Assert.AreEqual(9, bus.TotalItemsCount);
Assert.IsInstanceOfType(bus.DequeueItemAsync(CancellationToken.None).Result.Packet, typeof(MqttPublishPacket));
Assert.IsInstanceOfType(bus.DequeueItemAsync(CancellationToken.None).Result.Packet, typeof(MqttSubAckPacket));
Assert.IsInstanceOfType(bus.DequeueItemAsync(CancellationToken.None).Result.Packet, typeof(MqttPingRespPacket));
Assert.IsInstanceOfType(bus.DequeueItemAsync(CancellationToken.None).Result.Packet, typeof(MqttPublishPacket));
Assert.IsInstanceOfType(bus.DequeueItemAsync(CancellationToken.None).Result.Packet, typeof(MqttSubAckPacket));
Assert.IsInstanceOfType(bus.DequeueItemAsync(CancellationToken.None).Result.Packet, typeof(MqttPingRespPacket));
Assert.IsInstanceOfType(bus.DequeueItemAsync(CancellationToken.None).Result.Packet, typeof(MqttPublishPacket));
Assert.IsInstanceOfType(bus.DequeueItemAsync(CancellationToken.None).Result.Packet, typeof(MqttSubAckPacket));
Assert.IsInstanceOfType(bus.DequeueItemAsync(CancellationToken.None).Result.Packet, typeof(MqttPingRespPacket));
Assert.AreEqual(0, bus.TotalItemsCount);
}
[TestMethod]
public void Await_Single_Packet()
{
var bus = new MqttPacketBus();
var delivered = false;
var item1 = new MqttPacketBusItem(new MqttPublishPacket());
var item2 = new MqttPacketBusItem(new MqttPublishPacket());
var item3 = new MqttPacketBusItem(new MqttPublishPacket());
item3.Completed += (_, _) =>
{
var bus = new MqttPacketBus();
delivered = true;
};
bus.EnqueueItem(new MqttPacketBusItem(new MqttPublishPacket()), MqttPacketBusPartition.Data);
bus.EnqueueItem(new MqttPacketBusItem(new MqttPublishPacket()), MqttPacketBusPartition.Data);
bus.EnqueueItem(new MqttPacketBusItem(new MqttPublishPacket()), MqttPacketBusPartition.Data);
bus.EnqueueItem(item1, MqttPacketBusPartition.Data);
bus.EnqueueItem(item2, MqttPacketBusPartition.Data);
bus.EnqueueItem(item3, MqttPacketBusPartition.Data);
bus.EnqueueItem(new MqttPacketBusItem(new MqttSubAckPacket()), MqttPacketBusPartition.Control);
bus.EnqueueItem(new MqttPacketBusItem(new MqttSubAckPacket()), MqttPacketBusPartition.Control);
bus.EnqueueItem(new MqttPacketBusItem(new MqttSubAckPacket()), MqttPacketBusPartition.Control);
Assert.IsFalse(delivered);
bus.EnqueueItem(new MqttPacketBusItem(new MqttPingRespPacket()), MqttPacketBusPartition.Health);
bus.EnqueueItem(new MqttPacketBusItem(new MqttPingRespPacket()), MqttPacketBusPartition.Health);
bus.EnqueueItem(new MqttPacketBusItem(new MqttPingRespPacket()), MqttPacketBusPartition.Health);
bus.DequeueItemAsync(CancellationToken.None).Result.Complete();
Assert.AreEqual(9, bus.TotalItemsCount);
Assert.IsFalse(delivered);
Assert.IsInstanceOfType(bus.DequeueItemAsync(CancellationToken.None).Result.Packet, typeof(MqttPublishPacket));
Assert.IsInstanceOfType(bus.DequeueItemAsync(CancellationToken.None).Result.Packet, typeof(MqttSubAckPacket));
Assert.IsInstanceOfType(bus.DequeueItemAsync(CancellationToken.None).Result.Packet, typeof(MqttPingRespPacket));
Assert.IsInstanceOfType(bus.DequeueItemAsync(CancellationToken.None).Result.Packet, typeof(MqttPublishPacket));
Assert.IsInstanceOfType(bus.DequeueItemAsync(CancellationToken.None).Result.Packet, typeof(MqttSubAckPacket));
Assert.IsInstanceOfType(bus.DequeueItemAsync(CancellationToken.None).Result.Packet, typeof(MqttPingRespPacket));
Assert.IsInstanceOfType(bus.DequeueItemAsync(CancellationToken.None).Result.Packet, typeof(MqttPublishPacket));
Assert.IsInstanceOfType(bus.DequeueItemAsync(CancellationToken.None).Result.Packet, typeof(MqttSubAckPacket));
Assert.IsInstanceOfType(bus.DequeueItemAsync(CancellationToken.None).Result.Packet, typeof(MqttPingRespPacket));
bus.DequeueItemAsync(CancellationToken.None).Result.Complete();
Assert.AreEqual(0, bus.TotalItemsCount);
}
Assert.IsFalse(delivered);
[TestMethod]
public void Await_Single_Packet()
{
var bus = new MqttPacketBus();
bus.DequeueItemAsync(CancellationToken.None).Result.Complete();
var delivered = false;
// The third packet has the event attached.
Assert.IsTrue(delivered);
}
var item1 = new MqttPacketBusItem(new MqttPublishPacket());
var item2 = new MqttPacketBusItem(new MqttPublishPacket());
[TestMethod]
public void Export_Packets_Without_Dequeue()
{
var bus = new MqttPacketBus();
var item3 = new MqttPacketBusItem(new MqttPublishPacket());
item3.Completed += (_, __) =>
bus.EnqueueItem(new MqttPacketBusItem(new MqttPublishPacket()), MqttPacketBusPartition.Data);
bus.EnqueueItem(new MqttPacketBusItem(new MqttPublishPacket()), MqttPacketBusPartition.Data);
bus.EnqueueItem(new MqttPacketBusItem(new MqttPublishPacket()), MqttPacketBusPartition.Data);
Assert.AreEqual(3, bus.TotalItemsCount);
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.TotalItemsCount);
}
[TestMethod]
public async Task Fill_From_Different_Task()
{
const int messageCount = 500;
var delayRandom = new Random();
var bus = new MqttPacketBus();
_ = Task.Run(
() =>
{
delivered = true;
};
bus.EnqueueItem(item1, MqttPacketBusPartition.Data);
bus.EnqueueItem(item2, MqttPacketBusPartition.Data);
bus.EnqueueItem(item3, MqttPacketBusPartition.Data);
Assert.IsFalse(delivered);
bus.DequeueItemAsync(CancellationToken.None).Result.Complete();
Assert.IsFalse(delivered);
bus.DequeueItemAsync(CancellationToken.None).Result.Complete();
Assert.IsFalse(delivered);
bus.DequeueItemAsync(CancellationToken.None).Result.Complete();
// The third packet has the event attached.
Assert.IsTrue(delivered);
}
[TestMethod]
public void Export_Packets_Without_Dequeue()
{
var bus = new MqttPacketBus();
bus.EnqueueItem(new MqttPacketBusItem(new MqttPublishPacket()), MqttPacketBusPartition.Data);
bus.EnqueueItem(new MqttPacketBusItem(new MqttPublishPacket()), MqttPacketBusPartition.Data);
bus.EnqueueItem(new MqttPacketBusItem(new MqttPublishPacket()), MqttPacketBusPartition.Data);
Assert.AreEqual(3, bus.TotalItemsCount);
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.TotalItemsCount);
}
[TestMethod]
public async Task Fill_From_Different_Task()
{
const int MessageCount = 500;
var delayRandom = new Random();
var bus = new MqttPacketBus();
_ = Task.Run(
() =>
for (var i = 0; i < messageCount; i++)
{
for (var i = 0; i < MessageCount; i++)
{
bus.EnqueueItem(new MqttPacketBusItem(MqttPingReqPacket.Instance), MqttPacketBusPartition.Health);
bus.EnqueueItem(new MqttPacketBusItem(MqttPingReqPacket.Instance), MqttPacketBusPartition.Health);
Thread.Sleep(delayRandom.Next(0, 10));
}
});
for (var i = 0; i < MessageCount; i++)
{
using (var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10)))
{
await bus.DequeueItemAsync(timeout.Token);
Thread.Sleep(delayRandom.Next(0, 10));
}
}
});
Assert.AreEqual(0, bus.TotalItemsCount);
}
[TestMethod]
[ExpectedException(typeof(TaskCanceledException))]
public async Task Wait_With_Empty_Bus()
for (var i = 0; i < messageCount; i++)
{
var bus = new MqttPacketBus();
using (var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(1)))
{
await bus.DequeueItemAsync(timeout.Token);
}
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10));
await bus.DequeueItemAsync(timeout.Token);
}
Assert.AreEqual(0, bus.TotalItemsCount);
}
[TestMethod]
[ExpectedException(typeof(TaskCanceledException))]
public async Task Wait_With_Empty_Bus()
{
var bus = new MqttPacketBus();
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(1));
await bus.DequeueItemAsync(timeout.Token);
}
}