SchedulerTest.cs 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT License.
  3. // See the LICENSE file in the project root for more information.
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Reactive.Concurrency;
  8. using System.Reactive.Disposables;
  9. using System.Reactive.Linq;
  10. using System.Reactive.PlatformServices;
  11. using System.Runtime.CompilerServices;
  12. using System.Threading;
  13. using Microsoft.VisualStudio.TestTools.UnitTesting;
  14. using Microsoft.Reactive.Testing;
  15. #if HAS_WINFORMS
  16. using System.Windows.Forms;
  17. using LegacyControlScheduler = System.Reactive.Concurrency.ControlScheduler;
  18. using ControlScheduler = System.Reactive.Integration.WindowsForms.ControlScheduler;
  19. #endif
  20. #if HAS_WPF
  21. using LegacyDispatcherScheduler = System.Reactive.Concurrency.DispatcherScheduler;
  22. using DispatcherScheduler = System.Reactive.Integration.Wpf.DispatcherScheduler;
  23. #endif
  24. using System.Threading.Tasks;
  25. using Assert = Xunit.Assert;
  26. namespace ReactiveTests.Tests
  27. {
  28. [TestClass]
  29. public class SchedulerTest : ReactiveTest
  30. {
  31. #region IScheduler
  32. [TestMethod]
  33. public void Scheduler_ArgumentChecks()
  34. {
  35. var ms = new MyScheduler();
  36. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(default, a => { }));
  37. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(default, () => { }));
  38. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleAction(default, new object(), state => { }));
  39. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(default, 1, (a, s) => { }));
  40. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(ms, default(Action<Action>)));
  41. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(ms, 1, default));
  42. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(default, DateTimeOffset.Now, a => { }));
  43. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(default, DateTimeOffset.Now, () => { }));
  44. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(default, 1, DateTimeOffset.Now, (a, s) => { }));
  45. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(ms, DateTimeOffset.Now, default(Action<Action<DateTimeOffset>>)));
  46. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(ms, 1, DateTimeOffset.Now, default));
  47. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(default, TimeSpan.Zero, a => { }));
  48. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(default, TimeSpan.Zero, () => { }));
  49. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(default, 1, TimeSpan.Zero, (a, s) => { }));
  50. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(ms, TimeSpan.Zero, default(Action<Action<TimeSpan>>)));
  51. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Schedule(ms, 1, TimeSpan.Zero, default));
  52. }
  53. [TestMethod]
  54. public void Schedulers_ArgumentChecks()
  55. {
  56. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.CurrentThread.Schedule(default(Action)));
  57. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.CurrentThread.ScheduleAction(new object(), default));
  58. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.CurrentThread.Schedule(TimeSpan.Zero, default(Action)));
  59. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.CurrentThread.Schedule(DateTimeOffset.MaxValue, default(Action)));
  60. #if DESKTOPCLR
  61. ReactiveAssert.Throws<ArgumentNullException>(() => DispatcherScheduler.Current.Schedule(default(Action)));
  62. ReactiveAssert.Throws<ArgumentNullException>(() => DispatcherScheduler.Current.ScheduleAction(new object(), default));
  63. ReactiveAssert.Throws<ArgumentNullException>(() => DispatcherScheduler.Current.Schedule(TimeSpan.Zero, default(Action)));
  64. ReactiveAssert.Throws<ArgumentNullException>(() => DispatcherScheduler.Current.Schedule(DateTimeOffset.MaxValue, default(Action)));
  65. ReactiveAssert.Throws<ArgumentNullException>(() => LegacyDispatcherScheduler.Current.Schedule(default(Action)));
  66. ReactiveAssert.Throws<ArgumentNullException>(() => LegacyDispatcherScheduler.Current.ScheduleAction(new object(), default));
  67. ReactiveAssert.Throws<ArgumentNullException>(() => LegacyDispatcherScheduler.Current.Schedule(TimeSpan.Zero, default(Action)));
  68. ReactiveAssert.Throws<ArgumentNullException>(() => LegacyDispatcherScheduler.Current.Schedule(DateTimeOffset.MaxValue, default(Action)));
  69. #endif
  70. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Immediate.Schedule(default(Action)));
  71. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Immediate.ScheduleAction(new object(), default));
  72. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Immediate.Schedule(TimeSpan.Zero, default(Action)));
  73. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Immediate.Schedule(DateTimeOffset.MaxValue, default(Action)));
  74. ReactiveAssert.Throws<ArgumentNullException>(() => NewThreadScheduler.Default.Schedule(default(Action)));
  75. ReactiveAssert.Throws<ArgumentNullException>(() => NewThreadScheduler.Default.ScheduleAction(new object(), default));
  76. ReactiveAssert.Throws<ArgumentNullException>(() => NewThreadScheduler.Default.Schedule(TimeSpan.Zero, default(Action)));
  77. ReactiveAssert.Throws<ArgumentNullException>(() => NewThreadScheduler.Default.Schedule(DateTimeOffset.MaxValue, default(Action)));
  78. ReactiveAssert.Throws<ArgumentNullException>(() => TaskPoolScheduler.Default.Schedule(default(Action)));
  79. ReactiveAssert.Throws<ArgumentNullException>(() => TaskPoolScheduler.Default.ScheduleAction(new object(), default));
  80. ReactiveAssert.Throws<ArgumentNullException>(() => TaskPoolScheduler.Default.Schedule(TimeSpan.Zero, default(Action)));
  81. ReactiveAssert.Throws<ArgumentNullException>(() => TaskPoolScheduler.Default.Schedule(DateTimeOffset.MaxValue, default(Action)));
  82. ReactiveAssert.Throws<ArgumentNullException>(() => DefaultScheduler.Instance.Schedule(default(Action)));
  83. ReactiveAssert.Throws<ArgumentNullException>(() => DefaultScheduler.Instance.ScheduleAction(new object(), default));
  84. ReactiveAssert.Throws<ArgumentNullException>(() => DefaultScheduler.Instance.Schedule(TimeSpan.Zero, default(Action)));
  85. ReactiveAssert.Throws<ArgumentNullException>(() => DefaultScheduler.Instance.Schedule(DateTimeOffset.MaxValue, default(Action)));
  86. ReactiveAssert.Throws<ArgumentNullException>(() => DefaultScheduler.Instance.SchedulePeriodic(42, TimeSpan.FromSeconds(1), default));
  87. ReactiveAssert.Throws<ArgumentOutOfRangeException>(() => DefaultScheduler.Instance.SchedulePeriodic(42, TimeSpan.FromSeconds(-1), _ => _));
  88. #if HAS_WINFORMS
  89. var lbl = new Label();
  90. ReactiveAssert.Throws<ArgumentNullException>(() => new ControlScheduler(lbl).Schedule(default(Action)));
  91. ReactiveAssert.Throws<ArgumentNullException>(() => new ControlScheduler(lbl).ScheduleAction(new object(), default(Action<object>)));
  92. ReactiveAssert.Throws<ArgumentNullException>(() => new ControlScheduler(lbl).Schedule(TimeSpan.Zero, default(Action)));
  93. ReactiveAssert.Throws<ArgumentNullException>(() => new ControlScheduler(lbl).Schedule(DateTimeOffset.MaxValue, default(Action)));
  94. ReactiveAssert.Throws<ArgumentNullException>(() => new LegacyControlScheduler(lbl).Schedule(default(Action)));
  95. ReactiveAssert.Throws<ArgumentNullException>(() => new LegacyControlScheduler(lbl).ScheduleAction(new object(), default(Action<object>)));
  96. ReactiveAssert.Throws<ArgumentNullException>(() => new LegacyControlScheduler(lbl).Schedule(TimeSpan.Zero, default(Action)));
  97. ReactiveAssert.Throws<ArgumentNullException>(() => new LegacyControlScheduler(lbl).Schedule(DateTimeOffset.MaxValue, default(Action)));
  98. #endif
  99. var ctx = new SynchronizationContext();
  100. ReactiveAssert.Throws<ArgumentNullException>(() => new SynchronizationContextScheduler(ctx).Schedule(default(Action)));
  101. /* Unmerged change from project 'Tests.System.Reactive(netcoreapp2.0)'
  102. Before:
  103. ReactiveAssert.Throws<ArgumentNullException>(() => new SynchronizationContextScheduler(ctx).ScheduleAction(new object(), default(Action<object>)));
  104. After:
  105. ReactiveAssert.Throws<ArgumentNullException>(() => new SynchronizationContextScheduler(ctx).ScheduleAction(new object(), default)));
  106. */
  107. /* Unmerged change from project 'Tests.System.Reactive(net46)'
  108. Before:
  109. ReactiveAssert.Throws<ArgumentNullException>(() => new SynchronizationContextScheduler(ctx).ScheduleAction(new object(), default(Action<object>)));
  110. After:
  111. ReactiveAssert.Throws<ArgumentNullException>(() => new SynchronizationContextScheduler(ctx).ScheduleAction(new object(), default)));
  112. */
  113. ReactiveAssert.Throws<ArgumentNullException>(() => new SynchronizationContextScheduler(ctx).ScheduleAction(new object(), default));
  114. ReactiveAssert.Throws<ArgumentNullException>(() => new SynchronizationContextScheduler(ctx).Schedule(TimeSpan.Zero, default(Action)));
  115. ReactiveAssert.Throws<ArgumentNullException>(() => new SynchronizationContextScheduler(ctx).Schedule(DateTimeOffset.MaxValue, default(Action)));
  116. }
  117. [TestMethod]
  118. public void Scheduler_ScheduleNonRecursive()
  119. {
  120. var ms = new MyScheduler();
  121. var res = false;
  122. Scheduler.Schedule(ms, a => { res = true; });
  123. Assert.True(res);
  124. }
  125. [TestMethod]
  126. public void Scheduler_ScheduleRecursive()
  127. {
  128. var ms = new MyScheduler();
  129. var i = 0;
  130. Scheduler.Schedule(ms, a => { if (++i < 10) { a(); } });
  131. Assert.Equal(10, i);
  132. }
  133. [TestMethod]
  134. public void Scheduler_Schedule_With_State()
  135. {
  136. var ms = new MyScheduler();
  137. var res = false;
  138. Scheduler.ScheduleAction(ms, "state", state => { Assert.Equal("state", state); res = true; });
  139. Assert.True(res);
  140. }
  141. [TestMethod]
  142. public void Scheduler_ScheduleWithTimeNonRecursive()
  143. {
  144. var now = DateTimeOffset.Now;
  145. var ms = new MyScheduler(now) { Check = (a, s, t) => { Assert.True(t == TimeSpan.Zero); } };
  146. var res = false;
  147. Scheduler.Schedule(ms, now, a => { res = true; });
  148. Assert.True(res);
  149. Assert.True(ms.WaitCycles == 0);
  150. }
  151. [TestMethod]
  152. public void Scheduler_ScheduleWithTimeRecursive()
  153. {
  154. var now = DateTimeOffset.Now;
  155. var i = 0;
  156. var ms = new MyScheduler(now) { Check = (a, s, t) => { Assert.True(t == TimeSpan.Zero); } };
  157. Scheduler.Schedule(ms, now, a => { if (++i < 10) { a(now); } });
  158. Assert.True(ms.WaitCycles == 0);
  159. Assert.Equal(10, i);
  160. }
  161. [TestMethod]
  162. public void Scheduler_ScheduleWithTimeSpanNonRecursive()
  163. {
  164. var now = DateTimeOffset.Now;
  165. var ms = new MyScheduler(now) { Check = (a, s, t) => { Assert.True(t == TimeSpan.Zero); } };
  166. var res = false;
  167. Scheduler.Schedule(ms, TimeSpan.Zero, a => { res = true; });
  168. Assert.True(res);
  169. Assert.True(ms.WaitCycles == 0);
  170. }
  171. [TestMethod]
  172. public void Scheduler_ScheduleWithTimeSpanRecursive()
  173. {
  174. var now = DateTimeOffset.Now;
  175. var ms = new MyScheduler(now) { Check = (a, s, t) => { Assert.True(t < TimeSpan.FromTicks(10)); } };
  176. var i = 0;
  177. Scheduler.Schedule(ms, TimeSpan.Zero, a => { if (++i < 10) { a(TimeSpan.FromTicks(i)); } });
  178. Assert.True(ms.WaitCycles == Enumerable.Range(1, 9).Sum());
  179. Assert.Equal(10, i);
  180. }
  181. [TestMethod]
  182. public void Scheduler_StateThreading()
  183. {
  184. var lst = new List<int>();
  185. Scheduler.Immediate.Schedule(0, (i, a) =>
  186. {
  187. lst.Add(i);
  188. if (i < 9)
  189. {
  190. a(i + 1);
  191. }
  192. });
  193. Assert.True(lst.SequenceEqual(Enumerable.Range(0, 10)));
  194. }
  195. [TestMethod]
  196. public void Scheduler_Builtins()
  197. {
  198. // Default
  199. {
  200. var e = new ManualResetEvent(false);
  201. Scheduler.Default.Schedule(() => e.Set());
  202. e.WaitOne();
  203. }
  204. Scheduler_Builtins_NoPlib();
  205. }
  206. [MethodImpl(MethodImplOptions.NoInlining)]
  207. private void Scheduler_Builtins_NoPlib()
  208. {
  209. // ThreadPool
  210. {
  211. var e = new ManualResetEvent(false);
  212. Scheduler.ThreadPool.Schedule(() => e.Set());
  213. e.WaitOne();
  214. }
  215. // NewThread
  216. {
  217. var e = new ManualResetEvent(false);
  218. Scheduler.NewThread.Schedule(() => e.Set());
  219. e.WaitOne();
  220. }
  221. // TaskPool
  222. {
  223. var e = new ManualResetEvent(false);
  224. Scheduler.TaskPool.Schedule(() => e.Set());
  225. e.WaitOne();
  226. }
  227. }
  228. #endregion
  229. #region ISchedulerLongRunning
  230. #if !NO_PERF
  231. #if !WINDOWS
  232. [TestMethod]
  233. public void Scheduler_LongRunning_ArgumentChecking()
  234. {
  235. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleLongRunning(null, c => { }));
  236. /* Unmerged change from project 'Tests.System.Reactive(net46)'
  237. Before:
  238. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleLongRunning(ThreadPoolScheduler.Instance, default(Action<ICancelable>)));
  239. After:
  240. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleLongRunning(ThreadPoolScheduler.Instance, default));
  241. */
  242. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleLongRunning(ThreadPoolScheduler.Instance, default));
  243. }
  244. [TestMethod]
  245. public void Scheduler_Periodic_ArgumentChecking()
  246. {
  247. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.SchedulePeriodic(null, TimeSpan.FromSeconds(1), () => { }));
  248. ReactiveAssert.Throws<ArgumentOutOfRangeException>(() => Scheduler.SchedulePeriodic(ThreadPoolScheduler.Instance, TimeSpan.FromSeconds(-1), () => { }));
  249. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.SchedulePeriodic(ThreadPoolScheduler.Instance, TimeSpan.FromSeconds(1), default));
  250. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.SchedulePeriodic(null, 42, TimeSpan.FromSeconds(1), _ => { }));
  251. ReactiveAssert.Throws<ArgumentOutOfRangeException>(() => Scheduler.SchedulePeriodic(ThreadPoolScheduler.Instance, 42, TimeSpan.FromSeconds(-1), _ => { }));
  252. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.SchedulePeriodic(ThreadPoolScheduler.Instance, 42, TimeSpan.FromSeconds(1), default(Action<int>)));
  253. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.SchedulePeriodic(null, 42, TimeSpan.FromSeconds(1), _ => _));
  254. ReactiveAssert.Throws<ArgumentOutOfRangeException>(() => Scheduler.SchedulePeriodic(ThreadPoolScheduler.Instance, 42, TimeSpan.FromSeconds(-1), _ => _));
  255. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.SchedulePeriodic(ThreadPoolScheduler.Instance, 42, TimeSpan.FromSeconds(1), default));
  256. }
  257. #endif
  258. [TestMethod]
  259. public void Scheduler_Stopwatch_Emulation()
  260. {
  261. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.StartStopwatch(null));
  262. }
  263. [TestMethod]
  264. public void Scheduler_LongRunning1()
  265. {
  266. var s = TaskPoolScheduler.Default;
  267. var x = new ManualResetEvent(false);
  268. var e = new ManualResetEvent(false);
  269. var d = s.ScheduleLongRunning(42, (state, cancel) =>
  270. {
  271. while (!cancel.IsDisposed)
  272. {
  273. x.Set();
  274. }
  275. e.Set();
  276. });
  277. x.WaitOne();
  278. d.Dispose();
  279. e.WaitOne();
  280. }
  281. [TestMethod]
  282. public void Scheduler_LongRunning2()
  283. {
  284. var s = TaskPoolScheduler.Default;
  285. var x = new ManualResetEvent(false);
  286. var e = new ManualResetEvent(false);
  287. var d = s.ScheduleLongRunning(cancel =>
  288. {
  289. while (!cancel.IsDisposed)
  290. {
  291. x.Set();
  292. }
  293. e.Set();
  294. });
  295. x.WaitOne();
  296. d.Dispose();
  297. e.WaitOne();
  298. }
  299. #endif
  300. #endregion
  301. #region ISchedulerPeriodic
  302. #if !NO_PERF
  303. #if !WINDOWS
  304. [TestMethod]
  305. public void Scheduler_Periodic1()
  306. {
  307. var n = 0;
  308. var e = new ManualResetEvent(false);
  309. var d = ThreadPoolScheduler.Instance.SchedulePeriodic(TimeSpan.FromMilliseconds(50), () =>
  310. {
  311. if (n++ == 10)
  312. {
  313. e.Set();
  314. }
  315. });
  316. e.WaitOne();
  317. d.Dispose();
  318. }
  319. [TestMethod]
  320. public void Scheduler_Periodic2()
  321. {
  322. var n = 0;
  323. var e = new ManualResetEvent(false);
  324. var d = ThreadPoolScheduler.Instance.SchedulePeriodic(42, TimeSpan.FromMilliseconds(50), x =>
  325. {
  326. Assert.Equal(42, x);
  327. if (n++ == 10)
  328. {
  329. e.Set();
  330. }
  331. });
  332. e.WaitOne();
  333. d.Dispose();
  334. }
  335. #endif
  336. #if DESKTOPCLR && NET472
  337. [TestMethod]
  338. public void Scheduler_Periodic_HostLifecycleManagement()
  339. {
  340. var cur = AppDomain.CurrentDomain.BaseDirectory;
  341. var domain = AppDomain.CreateDomain("HLN", null, new AppDomainSetup { ApplicationBase = cur });
  342. domain.DoCallBack(Scheduler_Periodic_HostLifecycleManagement_Callback);
  343. }
  344. private static void Scheduler_Periodic_HostLifecycleManagement_Callback()
  345. {
  346. var pep = PlatformEnlightenmentProvider.Current;
  347. try
  348. {
  349. var hln = new HLN();
  350. PlatformEnlightenmentProvider.Current = new PEP(hln);
  351. var s = ThreadPoolScheduler.Instance.DisableOptimizations(typeof(ISchedulerPeriodic));
  352. var n = 0;
  353. var e = new ManualResetEvent(false);
  354. var d = Observable.Interval(TimeSpan.FromMilliseconds(100), s).Subscribe(_ =>
  355. {
  356. if (n++ == 10)
  357. {
  358. e.Set();
  359. }
  360. });
  361. hln.OnSuspending();
  362. hln.OnResuming();
  363. Thread.Sleep(250);
  364. hln.OnSuspending();
  365. Thread.Sleep(150);
  366. hln.OnResuming();
  367. Thread.Sleep(50);
  368. hln.OnSuspending();
  369. hln.OnResuming();
  370. e.WaitOne();
  371. d.Dispose();
  372. }
  373. finally
  374. {
  375. PlatformEnlightenmentProvider.Current = pep;
  376. }
  377. }
  378. private class PEP : IPlatformEnlightenmentProvider
  379. {
  380. private readonly IPlatformEnlightenmentProvider _old;
  381. private readonly IHostLifecycleNotifications _hln;
  382. public PEP(HLN hln)
  383. {
  384. _old = PlatformEnlightenmentProvider.Current;
  385. _hln = hln;
  386. }
  387. public T GetService<T>(params object[] args) where T : class
  388. {
  389. if (typeof(T) == typeof(IHostLifecycleNotifications))
  390. {
  391. return (T)_hln;
  392. }
  393. return _old.GetService<T>(args);
  394. }
  395. }
  396. private class HLN : IHostLifecycleNotifications
  397. {
  398. public event EventHandler<HostSuspendingEventArgs> Suspending;
  399. public event EventHandler<HostResumingEventArgs> Resuming;
  400. public void OnSuspending()
  401. {
  402. Suspending?.Invoke(this, null);
  403. }
  404. public void OnResuming()
  405. {
  406. Resuming?.Invoke(this, null);
  407. }
  408. }
  409. #endif
  410. #endif
  411. #endregion
  412. #region DisableOptimizations
  413. #if !NO_PERF
  414. [TestMethod]
  415. public void DisableOptimizations_ArgumentChecking()
  416. {
  417. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.DisableOptimizations(default));
  418. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.DisableOptimizations(default, new Type[0]));
  419. #if !WINDOWS
  420. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.DisableOptimizations(ThreadPoolScheduler.Instance, default));
  421. #endif
  422. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.DisableOptimizations(Scheduler.Default).Schedule(42, default));
  423. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.DisableOptimizations(Scheduler.Default).Schedule(42, TimeSpan.FromSeconds(1), default));
  424. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.DisableOptimizations(Scheduler.Default).Schedule(42, DateTimeOffset.Now, default));
  425. }
  426. [TestMethod]
  427. public void DisableOptimizations1()
  428. {
  429. var s = TaskPoolScheduler.Default;
  430. Assert.True(s is IServiceProvider);
  431. var t = s.DisableOptimizations();
  432. var d = t.Now - s.Now;
  433. Assert.True(d.TotalSeconds < 1);
  434. var e1 = new ManualResetEvent(false);
  435. t.Schedule(42, (self, state) =>
  436. {
  437. e1.Set();
  438. return Disposable.Empty;
  439. });
  440. e1.WaitOne();
  441. var e2 = new ManualResetEvent(false);
  442. t.Schedule(42, TimeSpan.FromMilliseconds(1), (self, state) =>
  443. {
  444. e2.Set();
  445. return Disposable.Empty;
  446. });
  447. e2.WaitOne();
  448. var e3 = new ManualResetEvent(false);
  449. t.Schedule(42, DateTimeOffset.Now.AddMilliseconds(10), (self, state) =>
  450. {
  451. e3.Set();
  452. return Disposable.Empty;
  453. });
  454. e3.WaitOne();
  455. }
  456. [TestMethod]
  457. public void DisableOptimizations2()
  458. {
  459. var s = TaskPoolScheduler.Default;
  460. Assert.True(s is IServiceProvider);
  461. var lr1 = ((IServiceProvider)s).GetService(typeof(ISchedulerLongRunning));
  462. Assert.NotNull(lr1);
  463. var e1 = new ManualResetEvent(false);
  464. s.Schedule(42, (self, state) =>
  465. {
  466. Assert.True(self is IServiceProvider);
  467. var lrr1 = ((IServiceProvider)self).GetService(typeof(ISchedulerLongRunning));
  468. Assert.NotNull(lrr1);
  469. e1.Set();
  470. return Disposable.Empty;
  471. });
  472. e1.WaitOne();
  473. var t = s.DisableOptimizations();
  474. Assert.True(t is IServiceProvider);
  475. var lr2 = ((IServiceProvider)t).GetService(typeof(ISchedulerLongRunning));
  476. Assert.Null(lr2);
  477. var e2 = new ManualResetEvent(false);
  478. t.Schedule(42, (self, state) =>
  479. {
  480. Assert.True(self is IServiceProvider);
  481. var lrr2 = ((IServiceProvider)self).GetService(typeof(ISchedulerLongRunning));
  482. Assert.Null(lrr2);
  483. e2.Set();
  484. return Disposable.Empty;
  485. });
  486. e2.WaitOne();
  487. }
  488. [TestMethod]
  489. public void DisableOptimizations3()
  490. {
  491. var s = TaskPoolScheduler.Default;
  492. Assert.True(s is IServiceProvider);
  493. var lr1 = ((IServiceProvider)s).GetService(typeof(ISchedulerLongRunning));
  494. Assert.NotNull(lr1);
  495. var p1 = ((IServiceProvider)s).GetService(typeof(ISchedulerPeriodic));
  496. Assert.NotNull(p1);
  497. var e1 = new ManualResetEvent(false);
  498. s.Schedule(42, (self, state) =>
  499. {
  500. Assert.True(self is IServiceProvider);
  501. var lrr1 = ((IServiceProvider)self).GetService(typeof(ISchedulerLongRunning));
  502. Assert.NotNull(lrr1);
  503. var pr1 = ((IServiceProvider)self).GetService(typeof(ISchedulerPeriodic));
  504. Assert.NotNull(pr1);
  505. e1.Set();
  506. return Disposable.Empty;
  507. });
  508. e1.WaitOne();
  509. var t = s.DisableOptimizations(typeof(ISchedulerLongRunning));
  510. Assert.True(t is IServiceProvider);
  511. var lr2 = ((IServiceProvider)t).GetService(typeof(ISchedulerLongRunning));
  512. Assert.Null(lr2);
  513. var p2 = ((IServiceProvider)t).GetService(typeof(ISchedulerPeriodic));
  514. Assert.NotNull(p2);
  515. var e2 = new ManualResetEvent(false);
  516. t.Schedule(42, (self, state) =>
  517. {
  518. Assert.True(self is IServiceProvider);
  519. var lrr2 = ((IServiceProvider)self).GetService(typeof(ISchedulerLongRunning));
  520. Assert.Null(lrr2);
  521. var pr2 = ((IServiceProvider)self).GetService(typeof(ISchedulerPeriodic));
  522. Assert.NotNull(pr2);
  523. e2.Set();
  524. return Disposable.Empty;
  525. });
  526. e2.WaitOne();
  527. }
  528. #endif
  529. [TestMethod]
  530. public void DisableOptimizations_UnknownService()
  531. {
  532. var s = new MyScheduler();
  533. Assert.False(s is IServiceProvider);
  534. var d = s.DisableOptimizations();
  535. Assert.True(d is IServiceProvider);
  536. Assert.Null(((IServiceProvider)d).GetService(typeof(bool)));
  537. }
  538. private class MyScheduler : IScheduler
  539. {
  540. public MyScheduler()
  541. : this(DateTimeOffset.Now)
  542. {
  543. }
  544. public MyScheduler(DateTimeOffset now)
  545. {
  546. Now = now;
  547. }
  548. public DateTimeOffset Now
  549. {
  550. get;
  551. private set;
  552. }
  553. public IDisposable Schedule<T>(T state, Func<IScheduler, T, IDisposable> action)
  554. {
  555. return action(this, state);
  556. }
  557. public Action<Action<object>, object, TimeSpan> Check { get; set; }
  558. public long WaitCycles { get; set; }
  559. public IDisposable Schedule<T>(T state, TimeSpan dueTime, Func<IScheduler, T, IDisposable> action)
  560. {
  561. Check(o => action(this, (T)o), state, dueTime);
  562. WaitCycles += dueTime.Ticks;
  563. return action(this, state);
  564. }
  565. public IDisposable Schedule<T>(T state, DateTimeOffset dueTime, Func<IScheduler, T, IDisposable> action)
  566. {
  567. return Schedule(state, dueTime - Now, action);
  568. }
  569. }
  570. #endregion
  571. #region Catch
  572. [TestMethod]
  573. public void Catch_ArgumentChecking()
  574. {
  575. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Catch<Exception>(default, _ => true));
  576. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Catch<Exception>(Scheduler.Default, default));
  577. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Catch<Exception>(Scheduler.Default, _ => true).Schedule(42, default));
  578. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Catch<Exception>(Scheduler.Default, _ => true).Schedule(42, TimeSpan.FromSeconds(1), default));
  579. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Catch<Exception>(Scheduler.Default, _ => true).Schedule(42, DateTimeOffset.Now, default));
  580. }
  581. [TestMethod]
  582. public void Catch_Builtin_Swallow_Shallow()
  583. {
  584. var done = new ManualResetEvent(false);
  585. var swallow = Scheduler.Default.Catch<InvalidOperationException>(_ => { done.Set(); return true; });
  586. swallow.Schedule(() =>
  587. {
  588. throw new InvalidOperationException();
  589. });
  590. done.WaitOne();
  591. }
  592. [TestMethod]
  593. public void Catch_Builtin_Swallow_Recursive()
  594. {
  595. var done = new ManualResetEvent(false);
  596. var swallow = Scheduler.Default.Catch<InvalidOperationException>(_ => { done.Set(); return true; });
  597. swallow.Schedule(42, (self, state) =>
  598. {
  599. return self.Schedule(() =>
  600. {
  601. throw new InvalidOperationException();
  602. });
  603. });
  604. done.WaitOne();
  605. }
  606. [TestMethod]
  607. public void Catch_Custom_Unhandled()
  608. {
  609. var err = default(Exception);
  610. var scheduler = new MyExceptionScheduler(ex_ => err = ex_);
  611. scheduler.Catch<InvalidOperationException>(_ => true).Schedule(() =>
  612. {
  613. throw new InvalidOperationException();
  614. });
  615. Assert.Null(err);
  616. var ex = new ArgumentException();
  617. scheduler.Catch<InvalidOperationException>(_ => true).Schedule(() =>
  618. {
  619. throw ex;
  620. });
  621. Assert.Same(ex, err);
  622. }
  623. [TestMethod]
  624. public void Catch_Custom_Rethrow()
  625. {
  626. var err = default(Exception);
  627. var scheduler = new MyExceptionScheduler(ex_ => err = ex_);
  628. var ex = new InvalidOperationException();
  629. scheduler.Catch<InvalidOperationException>(_ => false).Schedule(() =>
  630. {
  631. throw ex;
  632. });
  633. Assert.Same(ex, err);
  634. }
  635. [TestMethod]
  636. public void Catch_Custom_LongRunning_Caught()
  637. {
  638. var err = default(Exception);
  639. var scheduler = new MyExceptionScheduler(ex_ => err = ex_);
  640. var caught = false;
  641. var @catch = scheduler.Catch<InvalidOperationException>(_ => caught = true);
  642. var slr = (ISchedulerLongRunning)((IServiceProvider)@catch).GetService(typeof(ISchedulerLongRunning));
  643. slr.ScheduleLongRunning(cancel =>
  644. {
  645. throw new InvalidOperationException();
  646. });
  647. Assert.True(caught);
  648. Assert.Null(err);
  649. var ex = new ArgumentException();
  650. slr.ScheduleLongRunning(cancel =>
  651. {
  652. throw ex;
  653. });
  654. Assert.Same(ex, err);
  655. }
  656. [TestMethod]
  657. public void Catch_Custom_LongRunning_Rethrow()
  658. {
  659. var err = default(Exception);
  660. var scheduler = new MyExceptionScheduler(ex_ => err = ex_);
  661. var @catch = scheduler.Catch<InvalidOperationException>(_ => false);
  662. var slr = (ISchedulerLongRunning)((IServiceProvider)@catch).GetService(typeof(ISchedulerLongRunning));
  663. var done = false;
  664. slr.ScheduleLongRunning(cancel =>
  665. {
  666. done = true;
  667. });
  668. Assert.True(done);
  669. var ex = new InvalidOperationException();
  670. slr.ScheduleLongRunning(cancel =>
  671. {
  672. throw ex;
  673. });
  674. Assert.Same(ex, err);
  675. }
  676. [TestMethod]
  677. public void Catch_Custom_Periodic_Regular()
  678. {
  679. var scheduler = new MyExceptionScheduler(_ => { })
  680. {
  681. PeriodicStopped = new ManualResetEvent(false)
  682. };
  683. var @catch = scheduler.Catch<InvalidOperationException>(_ => true);
  684. var per = (ISchedulerPeriodic)((IServiceProvider)@catch).GetService(typeof(ISchedulerPeriodic));
  685. var madeProgress = new ManualResetEvent(false);
  686. var d = per.SchedulePeriodic(0, TimeSpan.Zero, x =>
  687. {
  688. if (x > 10)
  689. {
  690. madeProgress.Set();
  691. }
  692. return x + 1;
  693. });
  694. madeProgress.WaitOne();
  695. d.Dispose();
  696. scheduler.PeriodicStopped.WaitOne();
  697. }
  698. [TestMethod]
  699. public void Catch_Custom_Periodic_Uncaught1()
  700. {
  701. var err = default(Exception);
  702. var done = new ManualResetEvent(false);
  703. var scheduler = new MyExceptionScheduler(ex_ => { err = ex_; done.Set(); })
  704. {
  705. PeriodicStopped = new ManualResetEvent(false)
  706. };
  707. var @catch = scheduler.Catch<InvalidOperationException>(_ => true);
  708. var per = (ISchedulerPeriodic)((IServiceProvider)@catch).GetService(typeof(ISchedulerPeriodic));
  709. var ex = new ArgumentException();
  710. per.SchedulePeriodic(42, TimeSpan.Zero, x =>
  711. {
  712. throw ex;
  713. });
  714. scheduler.PeriodicStopped.WaitOne();
  715. done.WaitOne();
  716. Assert.Same(ex, err);
  717. }
  718. [TestMethod]
  719. public void Catch_Custom_Periodic_Uncaught2()
  720. {
  721. var err = default(Exception);
  722. var done = new ManualResetEvent(false);
  723. var scheduler = new MyExceptionScheduler(ex_ => { err = ex_; done.Set(); })
  724. {
  725. PeriodicStopped = new ManualResetEvent(false)
  726. };
  727. var @catch = scheduler.Catch<InvalidOperationException>(_ => false);
  728. var per = (ISchedulerPeriodic)((IServiceProvider)@catch).GetService(typeof(ISchedulerPeriodic));
  729. var ex = new InvalidOperationException();
  730. per.SchedulePeriodic(42, TimeSpan.Zero, x =>
  731. {
  732. throw ex;
  733. });
  734. scheduler.PeriodicStopped.WaitOne();
  735. done.WaitOne();
  736. Assert.Same(ex, err);
  737. }
  738. [TestMethod]
  739. public void Catch_Custom_Periodic_Caught()
  740. {
  741. var err = default(Exception);
  742. var scheduler = new MyExceptionScheduler(ex_ => err = ex_)
  743. {
  744. PeriodicStopped = new ManualResetEvent(false)
  745. };
  746. var caught = new ManualResetEvent(false);
  747. var @catch = scheduler.Catch<InvalidOperationException>(_ => { caught.Set(); return true; });
  748. var per = (ISchedulerPeriodic)((IServiceProvider)@catch).GetService(typeof(ISchedulerPeriodic));
  749. per.SchedulePeriodic(42, TimeSpan.Zero, x =>
  750. {
  751. throw new InvalidOperationException();
  752. });
  753. scheduler.PeriodicStopped.WaitOne();
  754. caught.WaitOne();
  755. Assert.Null(err);
  756. }
  757. private class MyExceptionScheduler : LocalScheduler, ISchedulerLongRunning, ISchedulerPeriodic
  758. {
  759. private readonly Action<Exception> _onError;
  760. public MyExceptionScheduler(Action<Exception> onError)
  761. {
  762. _onError = onError;
  763. }
  764. public override IDisposable Schedule<TState>(TState state, Func<IScheduler, TState, IDisposable> action)
  765. {
  766. try
  767. {
  768. return action(this, state);
  769. }
  770. catch (Exception exception)
  771. {
  772. _onError(exception);
  773. return Disposable.Empty;
  774. }
  775. }
  776. public override IDisposable Schedule<TState>(TState state, TimeSpan dueTime, Func<IScheduler, TState, IDisposable> action)
  777. {
  778. throw new NotImplementedException();
  779. }
  780. public IDisposable ScheduleLongRunning<TState>(TState state, Action<TState, ICancelable> action)
  781. {
  782. var b = new BooleanDisposable();
  783. try
  784. {
  785. action(state, b);
  786. }
  787. catch (Exception exception)
  788. {
  789. _onError(exception);
  790. return Disposable.Empty;
  791. }
  792. return b;
  793. }
  794. public ManualResetEvent PeriodicStopped { get; set; }
  795. public IDisposable SchedulePeriodic<TState>(TState state, TimeSpan period, Func<TState, TState> action)
  796. {
  797. var b = new BooleanDisposable();
  798. Scheduler.Default.Schedule(() =>
  799. {
  800. try
  801. {
  802. var s = state;
  803. for (var i = 0; true; i++)
  804. {
  805. if (i > 100 /* mimic delayed cancellation */ && b.IsDisposed)
  806. {
  807. break;
  808. }
  809. s = action(s);
  810. }
  811. }
  812. catch (Exception exception)
  813. {
  814. _onError(exception);
  815. }
  816. finally
  817. {
  818. PeriodicStopped.Set();
  819. }
  820. });
  821. return b;
  822. }
  823. }
  824. #endregion
  825. #region Services
  826. [TestMethod]
  827. public void InvalidService_Null()
  828. {
  829. var s = new MySchedulerWithoutServices();
  830. Assert.Null(((IServiceProvider)s).GetService(typeof(IAsyncResult)));
  831. }
  832. private class MySchedulerWithoutServices : LocalScheduler
  833. {
  834. public override IDisposable Schedule<TState>(TState state, TimeSpan dueTime, Func<IScheduler, TState, IDisposable> action)
  835. {
  836. throw new NotImplementedException();
  837. }
  838. }
  839. [TestMethod]
  840. public void DetectServices_Null_1()
  841. {
  842. var s = new MyDumbScheduler1();
  843. Assert.Null(Scheduler.AsLongRunning(s));
  844. Assert.Null(Scheduler.AsPeriodic(s));
  845. Assert.Null(Scheduler.AsStopwatchProvider(s));
  846. }
  847. private class MyDumbScheduler1 : IScheduler
  848. {
  849. public DateTimeOffset Now
  850. {
  851. get { throw new NotImplementedException(); }
  852. }
  853. public IDisposable Schedule<TState>(TState state, Func<IScheduler, TState, IDisposable> action)
  854. {
  855. throw new NotImplementedException();
  856. }
  857. public IDisposable Schedule<TState>(TState state, TimeSpan dueTime, Func<IScheduler, TState, IDisposable> action)
  858. {
  859. throw new NotImplementedException();
  860. }
  861. public IDisposable Schedule<TState>(TState state, DateTimeOffset dueTime, Func<IScheduler, TState, IDisposable> action)
  862. {
  863. throw new NotImplementedException();
  864. }
  865. }
  866. [TestMethod]
  867. public void DetectServices_Null_2()
  868. {
  869. var s = new MyDumbScheduler2([]);
  870. Assert.Null(Scheduler.AsLongRunning(s));
  871. Assert.Null(Scheduler.AsPeriodic(s));
  872. Assert.Null(Scheduler.AsStopwatchProvider(s));
  873. }
  874. [TestMethod]
  875. public void DetectServices_Found()
  876. {
  877. {
  878. var x = new MyLongRunning();
  879. var s = new MyDumbScheduler2(new Dictionary<Type, object>
  880. {
  881. { typeof(ISchedulerLongRunning), x }
  882. });
  883. Assert.Equal(x, Scheduler.AsLongRunning(s));
  884. }
  885. {
  886. var x = new MyStopwatchProvider();
  887. var s = new MyDumbScheduler2(new Dictionary<Type, object>
  888. {
  889. { typeof(IStopwatchProvider), x }
  890. });
  891. Assert.Equal(x, Scheduler.AsStopwatchProvider(s));
  892. }
  893. {
  894. var x = new MyPeriodic();
  895. var s = new MyDumbScheduler2(new Dictionary<Type, object>
  896. {
  897. { typeof(ISchedulerPeriodic), x }
  898. });
  899. Assert.Equal(x, Scheduler.AsPeriodic(s));
  900. }
  901. }
  902. private class MyDumbScheduler2 : IScheduler, IServiceProvider
  903. {
  904. private readonly Dictionary<Type, object> _services;
  905. public MyDumbScheduler2(Dictionary<Type, object> services)
  906. {
  907. _services = services;
  908. }
  909. public DateTimeOffset Now
  910. {
  911. get { throw new NotImplementedException(); }
  912. }
  913. public IDisposable Schedule<TState>(TState state, Func<IScheduler, TState, IDisposable> action)
  914. {
  915. throw new NotImplementedException();
  916. }
  917. public IDisposable Schedule<TState>(TState state, TimeSpan dueTime, Func<IScheduler, TState, IDisposable> action)
  918. {
  919. throw new NotImplementedException();
  920. }
  921. public IDisposable Schedule<TState>(TState state, DateTimeOffset dueTime, Func<IScheduler, TState, IDisposable> action)
  922. {
  923. throw new NotImplementedException();
  924. }
  925. public object GetService(Type serviceType)
  926. {
  927. if (_services.TryGetValue(serviceType, out var res))
  928. {
  929. return res;
  930. }
  931. return null;
  932. }
  933. }
  934. private class MyLongRunning : ISchedulerLongRunning
  935. {
  936. public IDisposable ScheduleLongRunning<TState>(TState state, Action<TState, ICancelable> action)
  937. {
  938. throw new NotImplementedException();
  939. }
  940. }
  941. private class MyStopwatchProvider : IStopwatchProvider
  942. {
  943. public IStopwatch StartStopwatch()
  944. {
  945. throw new NotImplementedException();
  946. }
  947. }
  948. private class MyPeriodic : ISchedulerPeriodic
  949. {
  950. public IDisposable SchedulePeriodic<TState>(TState state, TimeSpan period, Func<TState, TState> action)
  951. {
  952. throw new NotImplementedException();
  953. }
  954. }
  955. #endregion
  956. [TestMethod]
  957. public void SchedulerAsync_Yield_ArgumentChecking()
  958. {
  959. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Yield(default));
  960. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Yield(default, CancellationToken.None));
  961. }
  962. [TestMethod]
  963. public void SchedulerAsync_Sleep_ArgumentChecking()
  964. {
  965. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Sleep(default, TimeSpan.Zero));
  966. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Sleep(default, TimeSpan.Zero, CancellationToken.None));
  967. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Sleep(default, DateTimeOffset.MinValue));
  968. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.Sleep(default, DateTimeOffset.MinValue, CancellationToken.None));
  969. }
  970. [TestMethod]
  971. public void SchedulerAsync_ScheduleAsync_ArgumentChecking()
  972. {
  973. var tcs = new TaskCompletionSource<IDisposable>();
  974. var t = tcs.Task;
  975. var d = default(IScheduler);
  976. var s = Scheduler.Immediate;
  977. var rt = TimeSpan.Zero;
  978. var at = DateTimeOffset.MinValue;
  979. var a1 = new Func<IScheduler, int, CancellationToken, Task>((_, __, ___) => t);
  980. var d1 = default(Func<IScheduler, int, CancellationToken, Task>);
  981. var a2 = new Func<IScheduler, int, CancellationToken, Task<IDisposable>>((_, __, ___) => t);
  982. var d2 = default(Func<IScheduler, int, CancellationToken, Task<IDisposable>>);
  983. var a3 = new Func<IScheduler, CancellationToken, Task>((_, __) => t);
  984. var d3 = default(Func<IScheduler, CancellationToken, Task>);
  985. var a4 = new Func<IScheduler, CancellationToken, Task<IDisposable>>((_, __) => t);
  986. var d4 = default(Func<IScheduler, CancellationToken, Task<IDisposable>>);
  987. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleAsync(d, 42, a1));
  988. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleAsync(s, 42, d1));
  989. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleAsync(d, 42, rt, a1));
  990. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleAsync(s, 42, rt, d1));
  991. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleAsync(d, 42, at, a1));
  992. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleAsync(s, 42, at, d1));
  993. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleAsync(d, 42, a2));
  994. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleAsync(s, 42, d2));
  995. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleAsync(d, 42, rt, a2));
  996. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleAsync(s, 42, rt, d2));
  997. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleAsync(d, 42, at, a2));
  998. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleAsync(s, 42, at, d2));
  999. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleAsync(d, a3));
  1000. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleAsync(s, d3));
  1001. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleAsync(d, rt, a3));
  1002. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleAsync(s, rt, d3));
  1003. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleAsync(d, at, a3));
  1004. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleAsync(s, at, d3));
  1005. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleAsync(d, a4));
  1006. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleAsync(s, d4));
  1007. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleAsync(d, rt, a4));
  1008. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleAsync(s, rt, d4));
  1009. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleAsync(d, at, a4));
  1010. ReactiveAssert.Throws<ArgumentNullException>(() => Scheduler.ScheduleAsync(s, at, d4));
  1011. }
  1012. [TestMethod]
  1013. public void SchedulerAsync_ScheduleAsync_Overloads1()
  1014. {
  1015. var tcsI = new TaskCompletionSource<int>();
  1016. var t = tcsI.Task;
  1017. tcsI.SetResult(0);
  1018. var tcsD = new TaskCompletionSource<IDisposable>();
  1019. var d = tcsD.Task;
  1020. tcsD.SetResult(Disposable.Empty);
  1021. var s = new TestScheduler();
  1022. var o = s.CreateObserver<int>();
  1023. s.ScheduleAsync((_, ct) =>
  1024. {
  1025. o.OnNext(42);
  1026. return t;
  1027. });
  1028. s.ScheduleAsync((_, ct) =>
  1029. {
  1030. o.OnNext(43);
  1031. return d;
  1032. });
  1033. s.ScheduleAsync(44, (_, x, ct) =>
  1034. {
  1035. o.OnNext(x);
  1036. return t;
  1037. });
  1038. s.ScheduleAsync(45, (_, x, ct) =>
  1039. {
  1040. o.OnNext(45);
  1041. return d;
  1042. });
  1043. s.Start();
  1044. o.Messages.AssertEqual(
  1045. OnNext(1, 42),
  1046. OnNext(1, 43),
  1047. OnNext(1, 44),
  1048. OnNext(1, 45)
  1049. );
  1050. }
  1051. [TestMethod]
  1052. public void SchedulerAsync_ScheduleAsync_Overloads2()
  1053. {
  1054. var tcsI = new TaskCompletionSource<int>();
  1055. var t = tcsI.Task;
  1056. tcsI.SetResult(0);
  1057. var tcsD = new TaskCompletionSource<IDisposable>();
  1058. var d = tcsD.Task;
  1059. tcsD.SetResult(Disposable.Empty);
  1060. var s = new TestScheduler();
  1061. var o = s.CreateObserver<int>();
  1062. s.ScheduleAsync(TimeSpan.FromTicks(50), (_, ct) =>
  1063. {
  1064. o.OnNext(42);
  1065. return t;
  1066. });
  1067. s.ScheduleAsync(TimeSpan.FromTicks(60), (_, ct) =>
  1068. {
  1069. o.OnNext(43);
  1070. return d;
  1071. });
  1072. s.ScheduleAsync(44, TimeSpan.FromTicks(70), (_, x, ct) =>
  1073. {
  1074. o.OnNext(x);
  1075. return t;
  1076. });
  1077. s.ScheduleAsync(45, TimeSpan.FromTicks(80), (_, x, ct) =>
  1078. {
  1079. o.OnNext(45);
  1080. return d;
  1081. });
  1082. s.Start();
  1083. o.Messages.AssertEqual(
  1084. OnNext(50, 42),
  1085. OnNext(60, 43),
  1086. OnNext(70, 44),
  1087. OnNext(80, 45)
  1088. );
  1089. }
  1090. [TestMethod]
  1091. public void SchedulerAsync_ScheduleAsync_Overloads3()
  1092. {
  1093. var tcsI = new TaskCompletionSource<int>();
  1094. var t = tcsI.Task;
  1095. tcsI.SetResult(0);
  1096. var tcsD = new TaskCompletionSource<IDisposable>();
  1097. var d = tcsD.Task;
  1098. tcsD.SetResult(Disposable.Empty);
  1099. var s = new TestScheduler();
  1100. var o = s.CreateObserver<int>();
  1101. s.ScheduleAsync(new DateTimeOffset(50, TimeSpan.Zero), (_, ct) =>
  1102. {
  1103. o.OnNext(42);
  1104. return t;
  1105. });
  1106. s.ScheduleAsync(new DateTimeOffset(60, TimeSpan.Zero), (_, ct) =>
  1107. {
  1108. o.OnNext(43);
  1109. return d;
  1110. });
  1111. s.ScheduleAsync(44, new DateTimeOffset(70, TimeSpan.Zero), (_, x, ct) =>
  1112. {
  1113. o.OnNext(x);
  1114. return t;
  1115. });
  1116. s.ScheduleAsync(45, new DateTimeOffset(80, TimeSpan.Zero), (_, x, ct) =>
  1117. {
  1118. o.OnNext(45);
  1119. return d;
  1120. });
  1121. s.Start();
  1122. o.Messages.AssertEqual(
  1123. OnNext(50, 42),
  1124. OnNext(60, 43),
  1125. OnNext(70, 44),
  1126. OnNext(80, 45)
  1127. );
  1128. }
  1129. [TestMethod]
  1130. public void SchedulerAsync_ScheduleAsync_NoCancellation1()
  1131. {
  1132. var s = new TestScheduler();
  1133. var o = s.CreateObserver<int>();
  1134. s.ScheduleAsync(async (scheduler, _) =>
  1135. {
  1136. o.OnNext(42);
  1137. #pragma warning disable CA2016 // (Forward CancellationToken.) We are testing the methods that don't take a CancellationToken here
  1138. await scheduler.Yield();
  1139. o.OnNext(43);
  1140. await scheduler.Sleep(TimeSpan.FromTicks(10));
  1141. o.OnNext(44);
  1142. await scheduler.Sleep(new DateTimeOffset(250, TimeSpan.Zero));
  1143. #pragma warning restore CA2016
  1144. o.OnNext(45);
  1145. });
  1146. s.Start();
  1147. o.Messages.AssertEqual(
  1148. OnNext(1, 42),
  1149. OnNext(2, 43),
  1150. OnNext(12, 44),
  1151. OnNext(250, 45)
  1152. );
  1153. }
  1154. [TestMethod]
  1155. public void SchedulerAsync_ScheduleAsync_NoCancellation2()
  1156. {
  1157. var s = new TestScheduler();
  1158. var o = s.CreateObserver<int>();
  1159. s.ScheduleAsync(async (scheduler, ct) =>
  1160. {
  1161. o.OnNext(42);
  1162. await scheduler.Yield(ct);
  1163. o.OnNext(43);
  1164. await scheduler.Sleep(TimeSpan.FromTicks(10), ct);
  1165. o.OnNext(44);
  1166. await scheduler.Sleep(new DateTimeOffset(250, TimeSpan.Zero), ct);
  1167. o.OnNext(45);
  1168. });
  1169. s.Start();
  1170. o.Messages.AssertEqual(
  1171. OnNext(1, 42),
  1172. OnNext(2, 43),
  1173. OnNext(12, 44),
  1174. OnNext(250, 45)
  1175. );
  1176. }
  1177. [TestMethod]
  1178. public void SchedulerAsync_Awaiters()
  1179. {
  1180. var op = Scheduler.Immediate.Yield();
  1181. var aw = op.GetAwaiter();
  1182. ReactiveAssert.Throws<ArgumentNullException>(() => aw.OnCompleted(null));
  1183. aw.OnCompleted(() => { });
  1184. ReactiveAssert.Throws<InvalidOperationException>(() => aw.OnCompleted(() => { }));
  1185. }
  1186. [TestMethod]
  1187. public void SchedulerAsync_Yield_Cancel1()
  1188. {
  1189. var cts = new CancellationTokenSource();
  1190. var op = Scheduler.Immediate.Yield(cts.Token);
  1191. var aw = op.GetAwaiter();
  1192. cts.Cancel();
  1193. Assert.True(aw.IsCompleted);
  1194. ReactiveAssert.Throws<OperationCanceledException>(() => aw.GetResult());
  1195. }
  1196. [TestMethod]
  1197. public void SchedulerAsync_Yield_Cancel2()
  1198. {
  1199. var cts = new CancellationTokenSource();
  1200. var op = Scheduler.Immediate.Yield(cts.Token);
  1201. var aw = op.GetAwaiter();
  1202. Assert.False(aw.IsCompleted);
  1203. aw.OnCompleted(() =>
  1204. {
  1205. //
  1206. // TODO: Not needed for await pattern, but maybe should be wired up?
  1207. //
  1208. // Assert.True(aw.IsCompleted);
  1209. cts.Cancel();
  1210. ReactiveAssert.Throws<OperationCanceledException>(() => aw.GetResult());
  1211. });
  1212. }
  1213. [TestMethod]
  1214. public void SchedulerAsync_Sleep_Cancel()
  1215. {
  1216. var cts = new CancellationTokenSource();
  1217. var op = Scheduler.Default.Sleep(TimeSpan.FromHours(1), cts.Token);
  1218. var aw = op.GetAwaiter();
  1219. Assert.False(aw.IsCompleted);
  1220. var e = new ManualResetEvent(false);
  1221. aw.OnCompleted(() =>
  1222. {
  1223. ReactiveAssert.Throws<OperationCanceledException>(() => aw.GetResult());
  1224. e.Set();
  1225. });
  1226. cts.Cancel();
  1227. e.WaitOne();
  1228. }
  1229. [TestMethod]
  1230. public void SchedulerAsync_ScheduleAsync_SyncCtx()
  1231. {
  1232. var old = SynchronizationContext.Current;
  1233. try
  1234. {
  1235. var ctx = new MySyncCtx();
  1236. SynchronizationContext.SetSynchronizationContext(ctx);
  1237. var s = new TestScheduler();
  1238. var o = s.CreateObserver<int>();
  1239. s.ScheduleAsync(async (_, ct) =>
  1240. {
  1241. Assert.Same(ctx, SynchronizationContext.Current);
  1242. o.OnNext(42);
  1243. await _.Yield(ct).ConfigureAwait(true);
  1244. Assert.Same(ctx, SynchronizationContext.Current);
  1245. o.OnNext(43);
  1246. await _.Sleep(TimeSpan.FromTicks(10), ct).ConfigureAwait(true);
  1247. Assert.Same(ctx, SynchronizationContext.Current);
  1248. o.OnNext(44);
  1249. await _.Sleep(new DateTimeOffset(250, TimeSpan.Zero), ct).ConfigureAwait(true);
  1250. Assert.Same(ctx, SynchronizationContext.Current);
  1251. o.OnNext(45);
  1252. });
  1253. s.Start();
  1254. o.Messages.AssertEqual(
  1255. OnNext(1, 42),
  1256. OnNext(2, 43),
  1257. OnNext(12, 44),
  1258. OnNext(250, 45)
  1259. );
  1260. }
  1261. finally
  1262. {
  1263. SynchronizationContext.SetSynchronizationContext(old);
  1264. }
  1265. }
  1266. private class MySyncCtx : SynchronizationContext
  1267. {
  1268. public override void Post(SendOrPostCallback d, object state)
  1269. {
  1270. d(state);
  1271. }
  1272. }
  1273. }
  1274. }