|
|
@@ -1,237 +0,0 @@ |
|
|
|
using System; |
|
|
|
using System.Threading; |
|
|
|
using System.Threading.Tasks; |
|
|
|
using Microsoft.VisualStudio.TestTools.UnitTesting; |
|
|
|
using MQTTnet.Internal; |
|
|
|
|
|
|
|
namespace MQTTnet.Tests |
|
|
|
{ |
|
|
|
[TestClass] |
|
|
|
// Inspired from the vs-threading tests (https://github.com/Microsoft/vs-threading/blob/master/src/Microsoft.VisualStudio.Threading.Tests/AsyncAutoResetEventTests.cs) |
|
|
|
public class AsyncAutoResetEvent_Tests |
|
|
|
{ |
|
|
|
private readonly AsyncAutoResetEvent _aare; |
|
|
|
|
|
|
|
public AsyncAutoResetEvent_Tests() |
|
|
|
{ |
|
|
|
_aare = new AsyncAutoResetEvent(); |
|
|
|
} |
|
|
|
|
|
|
|
[TestMethod] |
|
|
|
public async Task Cleanup_Waiters() |
|
|
|
{ |
|
|
|
var @lock = new AsyncAutoResetEvent(); |
|
|
|
|
|
|
|
var waitOnePassed = false; |
|
|
|
|
|
|
|
#pragma warning disable 4014 |
|
|
|
Task.Run(async () => |
|
|
|
#pragma warning restore 4014 |
|
|
|
{ |
|
|
|
await @lock.WaitOneAsync(TimeSpan.FromSeconds(2)); |
|
|
|
waitOnePassed = true; |
|
|
|
}); |
|
|
|
|
|
|
|
await Task.Delay(500); |
|
|
|
|
|
|
|
Assert.AreEqual(1, @lock.WaitersCount); |
|
|
|
|
|
|
|
@lock.Set(); |
|
|
|
|
|
|
|
await Task.Delay(1000); |
|
|
|
|
|
|
|
Assert.IsTrue(waitOnePassed); |
|
|
|
Assert.AreEqual(0, @lock.WaitersCount); |
|
|
|
} |
|
|
|
|
|
|
|
[TestMethod] |
|
|
|
public async Task SingleThreadedPulse() |
|
|
|
{ |
|
|
|
for (int i = 0; i < 5; i++) |
|
|
|
{ |
|
|
|
var t = _aare.WaitOneAsync(); |
|
|
|
Assert.IsFalse(t.IsCompleted); |
|
|
|
_aare.Set(); |
|
|
|
await t; |
|
|
|
Assert.IsTrue(t.IsCompleted); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
[TestMethod] |
|
|
|
public async Task MultipleSetOnlySignalsOnce() |
|
|
|
{ |
|
|
|
_aare.Set(); |
|
|
|
_aare.Set(); |
|
|
|
await _aare.WaitOneAsync(); |
|
|
|
var t = _aare.WaitOneAsync(); |
|
|
|
Assert.IsFalse(t.IsCompleted); |
|
|
|
await Task.Delay(500); |
|
|
|
Assert.IsFalse(t.IsCompleted); |
|
|
|
_aare.Set(); |
|
|
|
await t; |
|
|
|
Assert.IsTrue(t.IsCompleted); |
|
|
|
} |
|
|
|
|
|
|
|
[TestMethod] |
|
|
|
public async Task OrderPreservingQueue() |
|
|
|
{ |
|
|
|
var waiters = new Task[5]; |
|
|
|
for (int i = 0; i < waiters.Length; i++) |
|
|
|
{ |
|
|
|
waiters[i] = _aare.WaitOneAsync(); |
|
|
|
} |
|
|
|
|
|
|
|
for (int i = 0; i < waiters.Length; i++) |
|
|
|
{ |
|
|
|
_aare.Set(); |
|
|
|
await waiters[i].ConfigureAwait(false); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// This test does not work in appveyor but on local machine it does!? |
|
|
|
/////// <summary> |
|
|
|
/////// Verifies that inlining continuations do not have to complete execution before Set() returns. |
|
|
|
/////// </summary> |
|
|
|
////[TestMethod] |
|
|
|
////public async Task SetReturnsBeforeInlinedContinuations() |
|
|
|
////{ |
|
|
|
//// var setReturned = new ManualResetEventSlim(); |
|
|
|
//// var inlinedContinuation = _aare.WaitOneAsync() |
|
|
|
//// .ContinueWith(delegate |
|
|
|
//// { |
|
|
|
//// // Arrange to synchronously block the continuation until Set() has returned, |
|
|
|
//// // which would deadlock if Set does not return until inlined continuations complete. |
|
|
|
//// Assert.IsTrue(setReturned.Wait(500)); |
|
|
|
//// }); |
|
|
|
//// await Task.Delay(100); |
|
|
|
//// _aare.Set(); |
|
|
|
//// setReturned.Set(); |
|
|
|
//// Assert.IsTrue(inlinedContinuation.Wait(500)); |
|
|
|
////} |
|
|
|
|
|
|
|
[TestMethod] |
|
|
|
public void WaitAsync_WithCancellationToken() |
|
|
|
{ |
|
|
|
var cts = new CancellationTokenSource(); |
|
|
|
Task waitTask = _aare.WaitOneAsync(cts.Token); |
|
|
|
Assert.IsFalse(waitTask.IsCompleted); |
|
|
|
|
|
|
|
// Cancel the request and ensure that it propagates to the task. |
|
|
|
cts.Cancel(); |
|
|
|
try |
|
|
|
{ |
|
|
|
waitTask.GetAwaiter().GetResult(); |
|
|
|
Assert.IsTrue(false, "Task was expected to transition to a canceled state."); |
|
|
|
} |
|
|
|
catch (OperationCanceledException) |
|
|
|
{ |
|
|
|
} |
|
|
|
|
|
|
|
// Now set the event and verify that a future waiter gets the signal immediately. |
|
|
|
_aare.Set(); |
|
|
|
waitTask = _aare.WaitOneAsync(); |
|
|
|
Assert.AreEqual(TaskStatus.WaitingForActivation, waitTask.Status); |
|
|
|
} |
|
|
|
|
|
|
|
[TestMethod] |
|
|
|
public void WaitAsync_WithCancellationToken_Precanceled() |
|
|
|
{ |
|
|
|
// We construct our own pre-canceled token so that we can do |
|
|
|
// a meaningful identity check later. |
|
|
|
var tokenSource = new CancellationTokenSource(); |
|
|
|
tokenSource.Cancel(); |
|
|
|
var token = tokenSource.Token; |
|
|
|
|
|
|
|
// Verify that a pre-set signal is not reset by a canceled wait request. |
|
|
|
_aare.Set(); |
|
|
|
try |
|
|
|
{ |
|
|
|
_aare.WaitOneAsync(token).GetAwaiter().GetResult(); |
|
|
|
Assert.IsTrue(false, "Task was expected to transition to a canceled state."); |
|
|
|
} |
|
|
|
catch (OperationCanceledException ex) |
|
|
|
{ |
|
|
|
Assert.AreEqual(token, ex.CancellationToken); |
|
|
|
} |
|
|
|
|
|
|
|
// Verify that the signal was not acquired. |
|
|
|
Task waitTask = _aare.WaitOneAsync(); |
|
|
|
Assert.AreEqual(TaskStatus.RanToCompletion, waitTask.Status); |
|
|
|
} |
|
|
|
|
|
|
|
[TestMethod] |
|
|
|
public async Task WaitAsync_WithTimeout() |
|
|
|
{ |
|
|
|
Task waitTask = _aare.WaitOneAsync(TimeSpan.FromMilliseconds(500)); |
|
|
|
Assert.IsFalse(waitTask.IsCompleted); |
|
|
|
|
|
|
|
// Cancel the request and ensure that it propagates to the task. |
|
|
|
await Task.Delay(1000).ConfigureAwait(false); |
|
|
|
try |
|
|
|
{ |
|
|
|
waitTask.GetAwaiter().GetResult(); |
|
|
|
Assert.IsTrue(false, "Task was expected to transition to a timeout state."); |
|
|
|
} |
|
|
|
catch (TimeoutException) |
|
|
|
{ |
|
|
|
Assert.IsTrue(true); |
|
|
|
} |
|
|
|
|
|
|
|
// Now set the event and verify that a future waiter gets the signal immediately. |
|
|
|
_aare.Set(); |
|
|
|
waitTask = _aare.WaitOneAsync(TimeSpan.FromMilliseconds(500)); |
|
|
|
Assert.AreEqual(TaskStatus.RanToCompletion, waitTask.Status); |
|
|
|
} |
|
|
|
|
|
|
|
[TestMethod] |
|
|
|
public void WaitAsync_Canceled_DoesNotInlineContinuations() |
|
|
|
{ |
|
|
|
var cts = new CancellationTokenSource(); |
|
|
|
var task = _aare.WaitOneAsync(cts.Token); |
|
|
|
|
|
|
|
var completingActionFinished = new ManualResetEventSlim(); |
|
|
|
var continuation = task.ContinueWith( |
|
|
|
_ => Assert.IsTrue(completingActionFinished.Wait(500)), |
|
|
|
CancellationToken.None, |
|
|
|
TaskContinuationOptions.None, |
|
|
|
TaskScheduler.Default); |
|
|
|
|
|
|
|
cts.Cancel(); |
|
|
|
completingActionFinished.Set(); |
|
|
|
|
|
|
|
// Rethrow the exception if it turned out it deadlocked. |
|
|
|
continuation.GetAwaiter().GetResult(); |
|
|
|
} |
|
|
|
|
|
|
|
[TestMethod] |
|
|
|
public async Task AsyncAutoResetEvent() |
|
|
|
{ |
|
|
|
var aare = new AsyncAutoResetEvent(); |
|
|
|
|
|
|
|
var globalI = 0; |
|
|
|
#pragma warning disable 4014 |
|
|
|
Task.Run(async () => |
|
|
|
#pragma warning restore 4014 |
|
|
|
{ |
|
|
|
await aare.WaitOneAsync(CancellationToken.None); |
|
|
|
globalI += 1; |
|
|
|
}); |
|
|
|
|
|
|
|
#pragma warning disable 4014 |
|
|
|
Task.Run(async () => |
|
|
|
#pragma warning restore 4014 |
|
|
|
{ |
|
|
|
await aare.WaitOneAsync(CancellationToken.None); |
|
|
|
globalI += 2; |
|
|
|
}); |
|
|
|
|
|
|
|
await Task.Delay(500); |
|
|
|
aare.Set(); |
|
|
|
await Task.Delay(500); |
|
|
|
aare.Set(); |
|
|
|
await Task.Delay(100); |
|
|
|
|
|
|
|
Assert.AreEqual(3, globalI); |
|
|
|
} |
|
|
|
} |
|
|
|
} |