TaskTest.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. //
  2. // TaskTest.cs
  3. //
  4. // Copyright (c) 2008 Jérémie "Garuma" Laval
  5. //
  6. // Permission is hereby granted, free of charge, to any person obtaining a copy
  7. // of this software and associated documentation files (the "Software"), to deal
  8. // in the Software without restriction, including without limitation the rights
  9. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. // copies of the Software, and to permit persons to whom the Software is
  11. // furnished to do so, subject to the following conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be included in
  14. // all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. // THE SOFTWARE.
  23. //
  24. //
  25. #if NET_4_0
  26. using System;
  27. using System.Threading;
  28. using System.Threading.Tasks;
  29. using NUnit.Framework;
  30. namespace MonoTests.System.Threading.Tasks
  31. {
  32. [TestFixture]
  33. public class TaskTests
  34. {
  35. Task[] tasks;
  36. const int max = 6;
  37. [SetUp]
  38. public void Setup()
  39. {
  40. tasks = new Task[max];
  41. }
  42. void InitWithDelegate(Action action)
  43. {
  44. for (int i = 0; i < max; i++) {
  45. tasks[i] = Task.Factory.StartNew(action);
  46. }
  47. }
  48. [Test]
  49. public void WaitAnyTest()
  50. {
  51. ParallelTestHelper.Repeat (delegate {
  52. int flag = 0;
  53. int finished = 0;
  54. InitWithDelegate(delegate {
  55. int times = Interlocked.Exchange (ref flag, 1);
  56. if (times == 1) {
  57. SpinWait sw = new SpinWait ();
  58. while (finished == 0) sw.SpinOnce ();
  59. } else {
  60. Interlocked.Increment (ref finished);
  61. }
  62. });
  63. int index = Task.WaitAny(tasks, 1000);
  64. Assert.AreNotEqual (-1, index, "#3");
  65. Assert.AreEqual (1, flag, "#1");
  66. Assert.AreEqual (1, finished, "#2");
  67. });
  68. }
  69. [Test]
  70. public void WaitAny_Empty ()
  71. {
  72. Assert.AreEqual (-1, Task.WaitAny (new Task[0]));
  73. }
  74. [Test]
  75. public void WaitAny_Zero ()
  76. {
  77. Assert.AreEqual (-1, Task.WaitAny (new Task[1] { new Task (delegate { })}, 0), "#1");
  78. Assert.AreEqual (-1, Task.WaitAny (new Task[1] { new Task (delegate { }) }, 20), "#1");
  79. }
  80. [Test]
  81. public void WaitAny_WithNull ()
  82. {
  83. var tasks = new [] {
  84. Task.FromResult (2),
  85. null
  86. };
  87. try {
  88. Task.WaitAny (tasks);
  89. Assert.Fail ();
  90. } catch (ArgumentException) {
  91. }
  92. }
  93. [Test]
  94. public void WaitAny_Cancelled ()
  95. {
  96. var cancelation = new CancellationTokenSource ();
  97. var tasks = new Task[] {
  98. new Task (delegate { }),
  99. new Task (delegate { }, cancelation.Token)
  100. };
  101. cancelation.Cancel ();
  102. Assert.AreEqual (1, Task.WaitAny (tasks, 1000), "#1");
  103. Assert.IsTrue (tasks[1].IsCompleted, "#2");
  104. Assert.IsTrue (tasks[1].IsCanceled, "#3");
  105. }
  106. [Test]
  107. public void WaitAny_CancelledWithoutExecution ()
  108. {
  109. var cancelation = new CancellationTokenSource ();
  110. var tasks = new Task[] {
  111. new Task (delegate { }),
  112. new Task (delegate { })
  113. };
  114. int res = 0;
  115. var mre = new ManualResetEventSlim (false);
  116. ThreadPool.QueueUserWorkItem (delegate {
  117. res = Task.WaitAny (tasks, 20);
  118. mre.Set ();
  119. });
  120. cancelation.Cancel ();
  121. Assert.IsTrue (mre.Wait (1000), "#1");
  122. Assert.AreEqual (-1, res);
  123. }
  124. [Test]
  125. public void WaitAny_OneException ()
  126. {
  127. var mre = new ManualResetEventSlim (false);
  128. var tasks = new Task[] {
  129. Task.Factory.StartNew (delegate { mre.Wait (1000); }),
  130. Task.Factory.StartNew (delegate { throw new ApplicationException (); })
  131. };
  132. Assert.AreEqual (1, Task.WaitAny (tasks, 1000), "#1");
  133. Assert.IsFalse (tasks[0].IsCompleted, "#2");
  134. Assert.IsTrue (tasks[1].IsFaulted, "#3");
  135. mre.Set ();
  136. }
  137. [Test]
  138. public void WaitAllTest()
  139. {
  140. ParallelTestHelper.Repeat (delegate {
  141. int achieved = 0;
  142. InitWithDelegate(delegate { Interlocked.Increment(ref achieved); });
  143. Task.WaitAll(tasks);
  144. Assert.AreEqual(max, achieved, "#1");
  145. });
  146. }
  147. [Test]
  148. public void WaitAll_Zero ()
  149. {
  150. Assert.IsFalse (Task.WaitAll (new Task[1] { new Task (delegate { }) }, 0), "#0");
  151. Assert.IsFalse (Task.WaitAll (new Task[1] { new Task (delegate { }) }, 10), "#1");
  152. }
  153. [Test]
  154. public void WaitAllWithExceptions ()
  155. {
  156. InitWithDelegate (delegate { throw new ApplicationException (); });
  157. try {
  158. Task.WaitAll (tasks);
  159. Assert.Fail ("#1");
  160. } catch (AggregateException e) {
  161. Assert.AreEqual (6, e.InnerExceptions.Count, "#2");
  162. }
  163. Assert.IsNotNull (tasks[0].Exception, "#3");
  164. }
  165. [Test]
  166. public void WaitAllCancelled ()
  167. {
  168. var cancelation = new CancellationTokenSource ();
  169. var tasks = new Task[] {
  170. new Task (delegate { cancelation.Cancel (); }),
  171. new Task (delegate { }, cancelation.Token)
  172. };
  173. tasks[0].Start ();
  174. try {
  175. Task.WaitAll (tasks);
  176. Assert.Fail ("#1");
  177. } catch (AggregateException e) {
  178. var inner = (TaskCanceledException) e.InnerException;
  179. Assert.AreEqual (tasks[1], inner.Task, "#2");
  180. }
  181. Assert.IsTrue (tasks[0].IsCompleted, "#3");
  182. Assert.IsTrue (tasks[1].IsCanceled, "#4");
  183. }
  184. [Test]
  185. public void WaitAllExceptionThenCancelled ()
  186. {
  187. var cancelation = new CancellationTokenSource ();
  188. var tasks = new Task[] {
  189. new Task (delegate { cancelation.Cancel (); throw new ApplicationException (); }),
  190. new Task (delegate { }, cancelation.Token)
  191. };
  192. tasks[0].Start ();
  193. try {
  194. Task.WaitAll (tasks);
  195. Assert.Fail ("#1");
  196. } catch (AggregateException e) {
  197. Assert.IsInstanceOfType (typeof (ApplicationException), e.InnerException, "#2");
  198. var inner = (TaskCanceledException) e.InnerExceptions[1];
  199. Assert.AreEqual (tasks[1], inner.Task, "#3");
  200. }
  201. Assert.IsTrue (tasks[0].IsCompleted, "#4");
  202. Assert.IsTrue (tasks[1].IsCanceled, "#5");
  203. }
  204. [Test]
  205. public void WaitAll_StartedUnderWait ()
  206. {
  207. var task1 = new Task (delegate { });
  208. ThreadPool.QueueUserWorkItem (delegate {
  209. // Sleep little to let task to start and hit internal wait
  210. Thread.Sleep (20);
  211. task1.Start ();
  212. });
  213. Assert.IsTrue (Task.WaitAll (new [] { task1 }, 1000), "#1");
  214. }
  215. [Test]
  216. public void CancelBeforeStart ()
  217. {
  218. var src = new CancellationTokenSource ();
  219. Task t = new Task (delegate { }, src.Token);
  220. src.Cancel ();
  221. Assert.AreEqual (TaskStatus.Canceled, t.Status, "#1");
  222. try {
  223. t.Start ();
  224. Assert.Fail ("#2");
  225. } catch (InvalidOperationException) {
  226. }
  227. }
  228. [Test]
  229. public void Wait_CancelledTask ()
  230. {
  231. var src = new CancellationTokenSource ();
  232. Task t = new Task (delegate { }, src.Token);
  233. src.Cancel ();
  234. try {
  235. t.Wait (1000);
  236. Assert.Fail ("#1");
  237. } catch (AggregateException e) {
  238. var details = (TaskCanceledException) e.InnerException;
  239. Assert.AreEqual (t, details.Task, "#1e");
  240. }
  241. try {
  242. t.Wait ();
  243. Assert.Fail ("#2");
  244. } catch (AggregateException e) {
  245. var details = (TaskCanceledException) e.InnerException;
  246. Assert.AreEqual (t, details.Task, "#2e");
  247. Assert.IsNull (details.Task.Exception, "#2e2");
  248. }
  249. }
  250. [Test, ExpectedException (typeof (InvalidOperationException))]
  251. public void CreationWhileInitiallyCanceled ()
  252. {
  253. var token = new CancellationToken (true);
  254. var task = new Task (() => { }, token);
  255. Assert.AreEqual (TaskStatus.Canceled, task.Status);
  256. task.Start ();
  257. }
  258. [Test]
  259. public void ContinueWithOnAnyTestCase()
  260. {
  261. ParallelTestHelper.Repeat (delegate {
  262. bool result = false;
  263. Task t = Task.Factory.StartNew(delegate { });
  264. Task cont = t.ContinueWith(delegate { result = true; }, TaskContinuationOptions.None);
  265. Assert.IsTrue (t.Wait (2000), "First wait, (status, {0})", t.Status);
  266. Assert.IsTrue (cont.Wait(2000), "Cont wait, (result, {0}) (parent status, {2}) (status, {1})", result, cont.Status, t.Status);
  267. Assert.IsNull(cont.Exception, "#1");
  268. Assert.IsNotNull(cont, "#2");
  269. Assert.IsTrue(result, "#3");
  270. });
  271. }
  272. [Test]
  273. public void ContinueWithOnCompletedSuccessfullyTestCase()
  274. {
  275. ParallelTestHelper.Repeat (delegate {
  276. bool result = false;
  277. Task t = Task.Factory.StartNew(delegate { });
  278. Task cont = t.ContinueWith(delegate { result = true; }, TaskContinuationOptions.OnlyOnRanToCompletion);
  279. Assert.IsTrue (t.Wait(1000), "#4");
  280. Assert.IsTrue (cont.Wait(1000), "#5");
  281. Assert.IsNull(cont.Exception, "#1");
  282. Assert.IsNotNull(cont, "#2");
  283. Assert.IsTrue(result, "#3");
  284. });
  285. }
  286. [Test]
  287. public void ContinueWithOnAbortedTestCase()
  288. {
  289. bool result = false;
  290. bool taskResult = false;
  291. CancellationTokenSource src = new CancellationTokenSource ();
  292. Task t = new Task (delegate { taskResult = true; }, src.Token);
  293. Task cont = t.ContinueWith (delegate { result = true; },
  294. TaskContinuationOptions.OnlyOnCanceled | TaskContinuationOptions.ExecuteSynchronously);
  295. src.Cancel ();
  296. Assert.AreEqual (TaskStatus.Canceled, t.Status, "#1a");
  297. Assert.IsTrue (cont.IsCompleted, "#1b");
  298. Assert.IsTrue (result, "#1c");
  299. try {
  300. t.Start ();
  301. Assert.Fail ("#2");
  302. } catch (InvalidOperationException) {
  303. }
  304. Assert.IsTrue (cont.Wait (1000), "#3");
  305. Assert.IsFalse (taskResult, "#4");
  306. Assert.IsNull (cont.Exception, "#5");
  307. Assert.AreEqual (TaskStatus.RanToCompletion, cont.Status, "#6");
  308. }
  309. [Test]
  310. public void ContinueWithOnFailedTestCase()
  311. {
  312. ParallelTestHelper.Repeat (delegate {
  313. bool result = false;
  314. Task t = Task.Factory.StartNew(delegate { throw new Exception("foo"); });
  315. Task cont = t.ContinueWith(delegate { result = true; }, TaskContinuationOptions.OnlyOnFaulted);
  316. Assert.IsTrue (cont.Wait(1000), "#0");
  317. Assert.IsNotNull (t.Exception, "#1");
  318. Assert.IsNotNull (cont, "#2");
  319. Assert.IsTrue (result, "#3");
  320. });
  321. }
  322. [Test]
  323. public void ContinueWithWithStart ()
  324. {
  325. Task t = new Task<int> (() => 1);
  326. t = t.ContinueWith (l => { });
  327. try {
  328. t.Start ();
  329. Assert.Fail ();
  330. } catch (InvalidOperationException) {
  331. }
  332. }
  333. [Test]
  334. public void ContinueWithChildren ()
  335. {
  336. ParallelTestHelper.Repeat (delegate {
  337. bool result = false;
  338. var t = Task.Factory.StartNew (() => Task.Factory.StartNew (() => {}, TaskCreationOptions.AttachedToParent));
  339. var mre = new ManualResetEvent (false);
  340. t.ContinueWith (l => {
  341. result = true;
  342. mre.Set ();
  343. });
  344. Assert.IsTrue (mre.WaitOne (1000), "#1");
  345. Assert.IsTrue (result, "#2");
  346. }, 2);
  347. }
  348. [Test]
  349. public void MultipleTasks()
  350. {
  351. ParallelTestHelper.Repeat (delegate {
  352. bool r1 = false, r2 = false, r3 = false;
  353. Task t1 = Task.Factory.StartNew(delegate {
  354. r1 = true;
  355. });
  356. Task t2 = Task.Factory.StartNew(delegate {
  357. r2 = true;
  358. });
  359. Task t3 = Task.Factory.StartNew(delegate {
  360. r3 = true;
  361. });
  362. t1.Wait(2000);
  363. t2.Wait(2000);
  364. t3.Wait(2000);
  365. Assert.IsTrue(r1, "#1");
  366. Assert.IsTrue(r2, "#2");
  367. Assert.IsTrue(r3, "#3");
  368. });
  369. }
  370. [Test]
  371. public void WaitChildTestCase()
  372. {
  373. ParallelTestHelper.Repeat (delegate {
  374. bool r1 = false, r2 = false, r3 = false;
  375. var mre = new ManualResetEvent (false);
  376. Task t = Task.Factory.StartNew(delegate {
  377. Task.Factory.StartNew(delegate {
  378. r1 = true;
  379. mre.Set ();
  380. }, TaskCreationOptions.AttachedToParent);
  381. Task.Factory.StartNew(delegate {
  382. Assert.IsTrue (mre.WaitOne (1000), "#0");
  383. r2 = true;
  384. }, TaskCreationOptions.AttachedToParent);
  385. Task.Factory.StartNew(delegate {
  386. Assert.IsTrue (mre.WaitOne (1000), "#0");
  387. r3 = true;
  388. }, TaskCreationOptions.AttachedToParent);
  389. });
  390. Assert.IsTrue (t.Wait(2000), "#0");
  391. Assert.IsTrue(r2, "#1");
  392. Assert.IsTrue(r3, "#2");
  393. Assert.IsTrue(r1, "#3");
  394. Assert.AreEqual (TaskStatus.RanToCompletion, t.Status, "#4");
  395. }, 10);
  396. }
  397. [Test]
  398. public void ExecuteSynchronouslyTest ()
  399. {
  400. var val = 0;
  401. Task t = new Task (() => { Thread.Sleep (100); val = 1; });
  402. t.RunSynchronously ();
  403. Assert.AreEqual (1, val);
  404. }
  405. [Test]
  406. public void RunSynchronouslyArgumentChecks ()
  407. {
  408. Task t = new Task (() => { });
  409. try {
  410. t.RunSynchronously (null);
  411. Assert.Fail ("#1");
  412. } catch (ArgumentNullException) {
  413. }
  414. }
  415. [Test]
  416. public void UnobservedExceptionOnFinalizerThreadTest ()
  417. {
  418. bool wasCalled = false;
  419. TaskScheduler.UnobservedTaskException += (o, args) => {
  420. wasCalled = true;
  421. args.SetObserved ();
  422. };
  423. var inner = new ApplicationException ();
  424. Task.Factory.StartNew (() => { throw inner; });
  425. Thread.Sleep (1000);
  426. GC.Collect ();
  427. Thread.Sleep (1000);
  428. GC.WaitForPendingFinalizers ();
  429. Assert.IsTrue (wasCalled);
  430. }
  431. [Test, ExpectedException (typeof (InvalidOperationException))]
  432. public void StartFinishedTaskTest ()
  433. {
  434. var t = Task.Factory.StartNew (delegate () { });
  435. t.Wait ();
  436. t.Start ();
  437. }
  438. [Test]
  439. public void Start_NullArgument ()
  440. {
  441. var t = Task.Factory.StartNew (delegate () { });
  442. try {
  443. t.Start (null);
  444. Assert.Fail ();
  445. } catch (ArgumentNullException) {
  446. }
  447. }
  448. [Test, ExpectedException (typeof (InvalidOperationException))]
  449. public void DisposeUnstartedTest ()
  450. {
  451. var t = new Task (() => { });
  452. t.Dispose ();
  453. }
  454. [Test]
  455. public void ThrowingUnrelatedCanceledExceptionTest ()
  456. {
  457. Task t = new Task (() => {
  458. throw new TaskCanceledException ();
  459. });
  460. t.RunSynchronously ();
  461. Assert.IsTrue (t.IsFaulted);
  462. Assert.IsFalse (t.IsCanceled);
  463. }
  464. #if NET_4_5
  465. [Test]
  466. public void FromResult ()
  467. {
  468. var t = Task.FromResult<object> (null);
  469. Assert.IsTrue (t.IsCompleted, "#1");
  470. Assert.AreEqual (null, t.Result, "#2");
  471. t.Dispose ();
  472. t.Dispose ();
  473. }
  474. [Test]
  475. public void Run_ArgumentCheck ()
  476. {
  477. try {
  478. Task.Run (null as Action);
  479. Assert.Fail ("#1");
  480. } catch (ArgumentNullException) {
  481. }
  482. }
  483. [Test]
  484. public void Run ()
  485. {
  486. var t = Task.Run (delegate { });
  487. Assert.AreEqual (TaskCreationOptions.DenyChildAttach, t.CreationOptions, "#1");
  488. t.Wait ();
  489. }
  490. [Test]
  491. public void Run_Cancel ()
  492. {
  493. var t = Task.Run (() => 1, new CancellationToken (true));
  494. try {
  495. var r = t.Result;
  496. Assert.Fail ("#1");
  497. } catch (AggregateException) {
  498. }
  499. Assert.IsTrue (t.IsCanceled, "#2");
  500. }
  501. [Test]
  502. public void Run_ExistingTask ()
  503. {
  504. var t = new Task<int> (() => 5);
  505. var t2 = Task.Run (() => { t.Start (); return t; });
  506. Assert.IsTrue (t2.Wait (1000), "#1");
  507. Assert.AreEqual (5, t2.Result, "#2");
  508. }
  509. #endif
  510. }
  511. }
  512. #endif