EventLoopSchedulerTest.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.Reactive.Concurrency;
  6. using System.Threading;
  7. using Microsoft.Reactive.Testing;
  8. using Microsoft.VisualStudio.TestTools.UnitTesting;
  9. #if STRESS
  10. using ReactiveTests.Stress.Schedulers;
  11. #endif
  12. namespace ReactiveTests.Tests
  13. {
  14. [TestClass]
  15. public class EventLoopSchedulerTest
  16. {
  17. [TestMethod]
  18. public void EventLoop_ArgumentChecking()
  19. {
  20. var el = new EventLoopScheduler();
  21. ReactiveAssert.Throws<ArgumentNullException>(() => new EventLoopScheduler(null));
  22. ReactiveAssert.Throws<ArgumentNullException>(() => el.Schedule<int>(42, default(Func<IScheduler, int, IDisposable>)));
  23. ReactiveAssert.Throws<ArgumentNullException>(() => el.Schedule<int>(42, DateTimeOffset.Now, default(Func<IScheduler, int, IDisposable>)));
  24. ReactiveAssert.Throws<ArgumentNullException>(() => el.Schedule<int>(42, TimeSpan.Zero, default(Func<IScheduler, int, IDisposable>)));
  25. ReactiveAssert.Throws<ArgumentNullException>(() => el.SchedulePeriodic(42, TimeSpan.FromSeconds(1), default(Func<int, int>)));
  26. ReactiveAssert.Throws<ArgumentOutOfRangeException>(() => el.SchedulePeriodic(42, TimeSpan.FromSeconds(-1), _ => _));
  27. }
  28. [TestMethod]
  29. public void EventLoop_Now()
  30. {
  31. var res = new EventLoopScheduler().Now - DateTime.Now;
  32. Assert.IsTrue(res.Seconds < 1);
  33. }
  34. [TestMethod]
  35. public void EventLoop_ScheduleAction()
  36. {
  37. var ran = false;
  38. var gate = new Semaphore(0, 1);
  39. var el = new EventLoopScheduler();
  40. el.Schedule(() => { ran = true;
  41. gate.Release(); });
  42. Assert.IsTrue(gate.WaitOne(TimeSpan.FromSeconds(2)));
  43. Assert.IsTrue(ran);
  44. }
  45. [TestMethod]
  46. public void EventLoop_DifferentThread()
  47. {
  48. var id = default(int);
  49. var gate = new Semaphore(0, 1);
  50. var el = new EventLoopScheduler();
  51. el.Schedule(() =>
  52. {
  53. id = Thread.CurrentThread.ManagedThreadId;
  54. gate.Release();
  55. });
  56. Assert.IsTrue(gate.WaitOne(TimeSpan.FromSeconds(2)));
  57. Assert.AreNotEqual(Thread.CurrentThread.ManagedThreadId, id);
  58. }
  59. [TestMethod]
  60. public void EventLoop_ScheduleOrderedActions()
  61. {
  62. var results = new List<int>();
  63. var gate = new Semaphore(0, 1);
  64. var el = new EventLoopScheduler();
  65. el.Schedule(() => results.Add(0));
  66. el.Schedule(() =>
  67. {
  68. results.Add(1);
  69. gate.Release();
  70. });
  71. Assert.IsTrue(gate.WaitOne(TimeSpan.FromSeconds(2)));
  72. results.AssertEqual(0, 1);
  73. }
  74. [TestMethod]
  75. public void EventLoop_SchedulerDisposed()
  76. {
  77. var d = 0;
  78. var e = new ManualResetEvent(false);
  79. var f = new ManualResetEvent(false);
  80. var results = new List<int>();
  81. var el = new EventLoopScheduler();
  82. el.Schedule(() => results.Add(0));
  83. el.Schedule(() =>
  84. {
  85. el.Dispose();
  86. e.Set();
  87. results.Add(1);
  88. try
  89. {
  90. el.Schedule(() => { throw new Exception("Should be disposed!"); });
  91. f.Set();
  92. }
  93. catch (ObjectDisposedException)
  94. {
  95. // BREAKING CHANGE v2 > v1.x - New exception behavior.
  96. Interlocked.Increment(ref d);
  97. f.Set();
  98. }
  99. });
  100. e.WaitOne();
  101. try
  102. {
  103. el.Schedule(() => results.Add(2));
  104. }
  105. catch (ObjectDisposedException)
  106. {
  107. // BREAKING CHANGE v2 > v1.x - New exception behavior.
  108. Interlocked.Increment(ref d);
  109. }
  110. f.WaitOne();
  111. results.AssertEqual(0, 1);
  112. Assert.AreEqual(2, d);
  113. }
  114. [TestMethod]
  115. public void EventLoop_ScheduleTimeOrderedActions()
  116. {
  117. var results = new List<int>();
  118. var gate = new Semaphore(0, 1);
  119. var el = new EventLoopScheduler();
  120. el.Schedule(TimeSpan.FromMilliseconds(50), () => results.Add(1));
  121. el.Schedule(TimeSpan.FromMilliseconds(100), () =>
  122. {
  123. results.Add(0);
  124. gate.Release();
  125. });
  126. Assert.IsTrue(gate.WaitOne(TimeSpan.FromSeconds(2)));
  127. results.AssertEqual(1, 0);
  128. }
  129. [TestMethod]
  130. public void EventLoop_ScheduleOrderedAndTimedActions()
  131. {
  132. var results = new List<int>();
  133. var gate = new Semaphore(0, 1);
  134. var el = new EventLoopScheduler();
  135. el.Schedule(() => results.Add(1));
  136. el.Schedule(TimeSpan.FromMilliseconds(100), () =>
  137. {
  138. results.Add(0);
  139. gate.Release();
  140. });
  141. Assert.IsTrue(gate.WaitOne(TimeSpan.FromSeconds(2)));
  142. results.AssertEqual(1, 0);
  143. }
  144. [TestMethod]
  145. public void EventLoop_ScheduleTimeOrderedInFlightActions()
  146. {
  147. var results = new List<int>();
  148. var gate = new Semaphore(0, 1);
  149. var el = new EventLoopScheduler();
  150. el.Schedule(TimeSpan.FromMilliseconds(100), () =>
  151. {
  152. results.Add(0);
  153. el.Schedule(TimeSpan.FromMilliseconds(50), () => results.Add(1));
  154. el.Schedule(TimeSpan.FromMilliseconds(100), ()=>
  155. {
  156. results.Add(2);
  157. gate.Release();
  158. });
  159. });
  160. Assert.IsTrue(gate.WaitOne(TimeSpan.FromSeconds(2)));
  161. results.AssertEqual(0, 1, 2);
  162. }
  163. [TestMethod]
  164. public void EventLoop_ScheduleTimeAndOrderedInFlightActions()
  165. {
  166. var results = new List<int>();
  167. var gate = new Semaphore(0, 1);
  168. var el = new EventLoopScheduler();
  169. el.Schedule(TimeSpan.FromMilliseconds(100), () =>
  170. {
  171. results.Add(0);
  172. el.Schedule(() => results.Add(4));
  173. el.Schedule(TimeSpan.FromMilliseconds(50), () => results.Add(1));
  174. el.Schedule(TimeSpan.FromMilliseconds(100), () =>
  175. {
  176. results.Add(2);
  177. gate.Release();
  178. });
  179. });
  180. Assert.IsTrue(gate.WaitOne(TimeSpan.FromSeconds(2)));
  181. results.AssertEqual(0, 4, 1, 2);
  182. }
  183. [TestMethod]
  184. public void EventLoop_ScheduleActionNested()
  185. {
  186. var ran = false;
  187. var el = new EventLoopScheduler();
  188. var gate = new Semaphore(0, 1);
  189. el.Schedule(() => el.Schedule(() => { ran = true;
  190. gate.Release(); }));
  191. Assert.IsTrue(gate.WaitOne(TimeSpan.FromSeconds(2)));
  192. Assert.IsTrue(ran);
  193. }
  194. #if !SILVERLIGHT
  195. [TestMethod]
  196. [Ignore]
  197. public void EventLoop_ScheduleActionDue()
  198. {
  199. var ran = false;
  200. var el = new EventLoopScheduler();
  201. var sw = new Stopwatch();
  202. var gate = new Semaphore(0, 1);
  203. sw.Start();
  204. el.Schedule(TimeSpan.FromSeconds(0.2), () => {
  205. ran = true;
  206. sw.Stop();
  207. gate.Release();
  208. });
  209. Assert.IsTrue(gate.WaitOne(TimeSpan.FromSeconds(2)));
  210. Assert.IsTrue(ran, "ran");
  211. Assert.IsTrue(sw.ElapsedMilliseconds > 180, "due " + sw.ElapsedMilliseconds);
  212. }
  213. [TestMethod]
  214. [Ignore]
  215. public void EventLoop_ScheduleActionDueNested()
  216. {
  217. var ran = false;
  218. var el = new EventLoopScheduler();
  219. var gate = new Semaphore(0, 1);
  220. var sw = new Stopwatch();
  221. sw.Start();
  222. el.Schedule(TimeSpan.FromSeconds(0.2), () =>
  223. {
  224. sw.Stop();
  225. sw.Start();
  226. el.Schedule(TimeSpan.FromSeconds(0.2), () =>
  227. {
  228. sw.Stop();
  229. ran = true;
  230. gate.Release();
  231. });
  232. });
  233. Assert.IsTrue(gate.WaitOne(TimeSpan.FromSeconds(2)));
  234. Assert.IsTrue(ran, "ran");
  235. Assert.IsTrue(sw.ElapsedMilliseconds > 380, "due " + sw.ElapsedMilliseconds);
  236. }
  237. #endif
  238. #if !NO_PERF
  239. #if !NO_STOPWATCH
  240. [TestMethod]
  241. public void Stopwatch()
  242. {
  243. StopwatchTest.Run(new EventLoopScheduler());
  244. }
  245. #endif
  246. #endif
  247. #if !NO_CDS
  248. [TestMethod]
  249. public void EventLoop_Immediate()
  250. {
  251. var M = 1000;
  252. var N = 4;
  253. for (int i = 0; i < N; i++)
  254. {
  255. for (int j = 1; j <= M; j *= 10)
  256. {
  257. using (var e = new EventLoopScheduler())
  258. {
  259. var cd = new CountdownEvent(j);
  260. for (int k = 0; k < j; k++)
  261. e.Schedule(() => cd.Signal());
  262. if (!cd.Wait(10000))
  263. Assert.Fail("j = " + j);
  264. }
  265. }
  266. }
  267. }
  268. [TestMethod]
  269. public void EventLoop_TimeCollisions()
  270. {
  271. var M = 1000;
  272. var N = 4;
  273. for (int i = 0; i < N; i++)
  274. {
  275. for (int j = 1; j <= M; j *= 10)
  276. {
  277. using (var e = new EventLoopScheduler())
  278. {
  279. var cd = new CountdownEvent(j);
  280. for (int k = 0; k < j; k++)
  281. e.Schedule(TimeSpan.FromMilliseconds(100), () => cd.Signal());
  282. if (!cd.Wait(10000))
  283. Assert.Fail("j = " + j);
  284. }
  285. }
  286. }
  287. }
  288. [TestMethod]
  289. public void EventLoop_Spread()
  290. {
  291. var M = 1000;
  292. var N = 4;
  293. for (int i = 0; i < N; i++)
  294. {
  295. for (int j = 1; j <= M; j *= 10)
  296. {
  297. using (var e = new EventLoopScheduler())
  298. {
  299. var cd = new CountdownEvent(j);
  300. for (int k = 0; k < j; k++)
  301. e.Schedule(TimeSpan.FromMilliseconds(k), () => cd.Signal());
  302. if (!cd.Wait(10000))
  303. Assert.Fail("j = " + j);
  304. }
  305. }
  306. }
  307. }
  308. #endif
  309. [TestMethod]
  310. public void EventLoop_Periodic()
  311. {
  312. var n = 0;
  313. using (var s = new EventLoopScheduler())
  314. {
  315. var e = new ManualResetEvent(false);
  316. var d = s.SchedulePeriodic(TimeSpan.FromMilliseconds(25), () =>
  317. {
  318. if (Interlocked.Increment(ref n) == 10)
  319. e.Set();
  320. });
  321. if (!e.WaitOne(10000))
  322. Assert.Fail();
  323. d.Dispose();
  324. }
  325. }
  326. #if STRESS
  327. [TestMethod]
  328. public void EventLoop_Stress()
  329. {
  330. EventLoop.NoSemaphoreFullException();
  331. }
  332. #endif
  333. }
  334. }