You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AsyncAutoResentEvent_Tests.cs 7.6 KiB

5 years ago
5 years ago
6 years ago
5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. using System;
  2. using System.Threading;
  3. using System.Threading.Tasks;
  4. using Microsoft.VisualStudio.TestTools.UnitTesting;
  5. using MQTTnet.Internal;
  6. namespace MQTTnet.Tests
  7. {
  8. [TestClass]
  9. // Inspired from the vs-threading tests (https://github.com/Microsoft/vs-threading/blob/master/src/Microsoft.VisualStudio.Threading.Tests/AsyncAutoResetEventTests.cs)
  10. public class AsyncAutoResetEvent_Tests
  11. {
  12. private readonly AsyncAutoResetEvent _aare;
  13. public AsyncAutoResetEvent_Tests()
  14. {
  15. _aare = new AsyncAutoResetEvent();
  16. }
  17. [TestMethod]
  18. public async Task Cleanup_Waiters()
  19. {
  20. var @lock = new AsyncAutoResetEvent();
  21. var waitOnePassed = false;
  22. #pragma warning disable 4014
  23. Task.Run(async () =>
  24. #pragma warning restore 4014
  25. {
  26. await @lock.WaitOneAsync(TimeSpan.FromSeconds(2));
  27. waitOnePassed = true;
  28. });
  29. await Task.Delay(500);
  30. Assert.AreEqual(1, @lock.WaitersCount);
  31. @lock.Set();
  32. await Task.Delay(1000);
  33. Assert.IsTrue(waitOnePassed);
  34. Assert.AreEqual(0, @lock.WaitersCount);
  35. }
  36. [TestMethod]
  37. public async Task SingleThreadedPulse()
  38. {
  39. for (int i = 0; i < 5; i++)
  40. {
  41. var t = _aare.WaitOneAsync();
  42. Assert.IsFalse(t.IsCompleted);
  43. _aare.Set();
  44. await t;
  45. Assert.IsTrue(t.IsCompleted);
  46. }
  47. }
  48. [TestMethod]
  49. public async Task MultipleSetOnlySignalsOnce()
  50. {
  51. _aare.Set();
  52. _aare.Set();
  53. await _aare.WaitOneAsync();
  54. var t = _aare.WaitOneAsync();
  55. Assert.IsFalse(t.IsCompleted);
  56. await Task.Delay(500);
  57. Assert.IsFalse(t.IsCompleted);
  58. _aare.Set();
  59. await t;
  60. Assert.IsTrue(t.IsCompleted);
  61. }
  62. [TestMethod]
  63. public async Task OrderPreservingQueue()
  64. {
  65. var waiters = new Task[5];
  66. for (int i = 0; i < waiters.Length; i++)
  67. {
  68. waiters[i] = _aare.WaitOneAsync();
  69. }
  70. for (int i = 0; i < waiters.Length; i++)
  71. {
  72. _aare.Set();
  73. await waiters[i].ConfigureAwait(false);
  74. }
  75. }
  76. // This test does not work in appveyor but on local machine it does!?
  77. /////// <summary>
  78. /////// Verifies that inlining continuations do not have to complete execution before Set() returns.
  79. /////// </summary>
  80. ////[TestMethod]
  81. ////public async Task SetReturnsBeforeInlinedContinuations()
  82. ////{
  83. //// var setReturned = new ManualResetEventSlim();
  84. //// var inlinedContinuation = _aare.WaitOneAsync()
  85. //// .ContinueWith(delegate
  86. //// {
  87. //// // Arrange to synchronously block the continuation until Set() has returned,
  88. //// // which would deadlock if Set does not return until inlined continuations complete.
  89. //// Assert.IsTrue(setReturned.Wait(500));
  90. //// });
  91. //// await Task.Delay(100);
  92. //// _aare.Set();
  93. //// setReturned.Set();
  94. //// Assert.IsTrue(inlinedContinuation.Wait(500));
  95. ////}
  96. [TestMethod]
  97. public void WaitAsync_WithCancellationToken()
  98. {
  99. var cts = new CancellationTokenSource();
  100. Task waitTask = _aare.WaitOneAsync(cts.Token);
  101. Assert.IsFalse(waitTask.IsCompleted);
  102. // Cancel the request and ensure that it propagates to the task.
  103. cts.Cancel();
  104. try
  105. {
  106. waitTask.GetAwaiter().GetResult();
  107. Assert.IsTrue(false, "Task was expected to transition to a canceled state.");
  108. }
  109. catch (OperationCanceledException)
  110. {
  111. }
  112. // Now set the event and verify that a future waiter gets the signal immediately.
  113. _aare.Set();
  114. waitTask = _aare.WaitOneAsync();
  115. Assert.AreEqual(TaskStatus.WaitingForActivation, waitTask.Status);
  116. }
  117. [TestMethod]
  118. public void WaitAsync_WithCancellationToken_Precanceled()
  119. {
  120. // We construct our own pre-canceled token so that we can do
  121. // a meaningful identity check later.
  122. var tokenSource = new CancellationTokenSource();
  123. tokenSource.Cancel();
  124. var token = tokenSource.Token;
  125. // Verify that a pre-set signal is not reset by a canceled wait request.
  126. _aare.Set();
  127. try
  128. {
  129. _aare.WaitOneAsync(token).GetAwaiter().GetResult();
  130. Assert.IsTrue(false, "Task was expected to transition to a canceled state.");
  131. }
  132. catch (OperationCanceledException ex)
  133. {
  134. Assert.AreEqual(token, ex.CancellationToken);
  135. }
  136. // Verify that the signal was not acquired.
  137. Task waitTask = _aare.WaitOneAsync();
  138. Assert.AreEqual(TaskStatus.RanToCompletion, waitTask.Status);
  139. }
  140. [TestMethod]
  141. public async Task WaitAsync_WithTimeout()
  142. {
  143. Task waitTask = _aare.WaitOneAsync(TimeSpan.FromMilliseconds(500));
  144. Assert.IsFalse(waitTask.IsCompleted);
  145. // Cancel the request and ensure that it propagates to the task.
  146. await Task.Delay(1000).ConfigureAwait(false);
  147. try
  148. {
  149. waitTask.GetAwaiter().GetResult();
  150. Assert.IsTrue(false, "Task was expected to transition to a timeout state.");
  151. }
  152. catch (TimeoutException)
  153. {
  154. Assert.IsTrue(true);
  155. }
  156. // Now set the event and verify that a future waiter gets the signal immediately.
  157. _aare.Set();
  158. waitTask = _aare.WaitOneAsync(TimeSpan.FromMilliseconds(500));
  159. Assert.AreEqual(TaskStatus.RanToCompletion, waitTask.Status);
  160. }
  161. [TestMethod]
  162. public void WaitAsync_Canceled_DoesNotInlineContinuations()
  163. {
  164. var cts = new CancellationTokenSource();
  165. var task = _aare.WaitOneAsync(cts.Token);
  166. var completingActionFinished = new ManualResetEventSlim();
  167. var continuation = task.ContinueWith(
  168. _ => Assert.IsTrue(completingActionFinished.Wait(500)),
  169. CancellationToken.None,
  170. TaskContinuationOptions.None,
  171. TaskScheduler.Default);
  172. cts.Cancel();
  173. completingActionFinished.Set();
  174. // Rethrow the exception if it turned out it deadlocked.
  175. continuation.GetAwaiter().GetResult();
  176. }
  177. [TestMethod]
  178. public async Task AsyncAutoResetEvent()
  179. {
  180. var aare = new AsyncAutoResetEvent();
  181. var globalI = 0;
  182. #pragma warning disable 4014
  183. Task.Run(async () =>
  184. #pragma warning restore 4014
  185. {
  186. await aare.WaitOneAsync(CancellationToken.None);
  187. globalI += 1;
  188. });
  189. #pragma warning disable 4014
  190. Task.Run(async () =>
  191. #pragma warning restore 4014
  192. {
  193. await aare.WaitOneAsync(CancellationToken.None);
  194. globalI += 2;
  195. });
  196. await Task.Delay(500);
  197. aare.Set();
  198. await Task.Delay(500);
  199. aare.Set();
  200. await Task.Delay(100);
  201. Assert.AreEqual(3, globalI);
  202. }
  203. }
  204. }