Merge pull request #498 from Unroll-Me/master
[mono.git] / mcs / class / corlib / Test / System.Threading.Tasks / TaskFactoryTest.cs
1 //
2 // TaskFactoryTest.cs
3 //
4 // Authors:
5 //       Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
6 //       Marek Safar <marek.safar@gmail.com>
7 // 
8 // Copyright (c) 2010 Jérémie "Garuma" Laval
9 // Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining a copy
12 // of this software and associated documentation files (the "Software"), to deal
13 // in the Software without restriction, including without limitation the rights
14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 // copies of the Software, and to permit persons to whom the Software is
16 // furnished to do so, subject to the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 // THE SOFTWARE.
28 //
29 //
30
31 #if NET_4_0 || MOBILE
32
33 using System;
34 using System.Threading;
35 using System.Threading.Tasks;
36 using System.Collections.Generic;
37
38 using NUnit.Framework;
39
40 namespace MonoTests.System.Threading.Tasks
41 {
42         [TestFixture]
43         public class TaskFactoryTests
44         {
45                 class CompletedAsyncResult : IAsyncResult
46                 {
47                         public object AsyncState
48                         {
49                                 get { throw new NotImplementedException (); }
50                         }
51
52                         public WaitHandle AsyncWaitHandle
53                         {
54                                 get { throw new NotImplementedException (); }
55                         }
56
57                         public bool CompletedSynchronously
58                         {
59                                 get { throw new NotImplementedException (); }
60                         }
61
62                         public bool IsCompleted
63                         {
64                                 get { return true; }
65                         }
66                 }
67
68                 class TestAsyncResult : IAsyncResult
69                 {
70                         WaitHandle wh = new ManualResetEvent (true);
71
72                         public object AsyncState
73                         {
74                                 get { throw new NotImplementedException (); }
75                         }
76
77                         public WaitHandle AsyncWaitHandle
78                         {
79                                 get
80                                 {
81                                         return wh;
82                                 }
83                         }
84
85                         public bool CompletedSynchronously
86                         {
87                                 get { throw new NotImplementedException (); }
88                         }
89
90                         public bool IsCompleted
91                         {
92                                 get { return false; }
93                         }
94                 }
95
96                 class TestScheduler : TaskScheduler
97                 {
98                         public bool ExecutedInline { get; set; }
99
100                         protected override void QueueTask (Task task)
101                         {
102                                 throw new NotImplementedException ();
103                         }
104
105                         protected override bool TryDequeue (Task task)
106                         {
107                                 throw new NotImplementedException ();
108                         }
109
110                         protected override bool TryExecuteTaskInline (Task task, bool taskWasPreviouslyQueued)
111                         {
112                                 if (taskWasPreviouslyQueued)
113                                         throw new ArgumentException ("taskWasPreviouslyQueued");
114
115                                 if (task.Status != TaskStatus.WaitingToRun)
116                                         throw new ArgumentException ("task.Status");
117
118                                 ExecutedInline = true;
119                                 return TryExecuteTask (task);
120                         }
121
122                         protected override IEnumerable<Task> GetScheduledTasks ()
123                         {
124                                 throw new NotImplementedException ();
125                         }
126                 }
127
128
129                 TaskFactory factory;
130
131                 [SetUp]
132                 public void Setup ()
133                 {
134                         this.factory = Task.Factory;
135                 }
136
137                 [Test]
138                 public void StartNewTest ()
139                 {
140                         bool result = false;
141                         factory.StartNew (() => result = true).Wait ();
142                         Assert.IsTrue (result);
143                 }
144
145                 [Test]
146                 public void NoDefaultScheduler ()
147                 {
148                         Assert.IsNull (factory.Scheduler, "#1");
149                 }
150
151                 [Test]
152                 public void ContinueWhenAll_Simple ()
153                 {
154                         var mre = new ManualResetEventSlim (false);
155
156                         Task[] tasks = new Task[3];
157                         tasks[0] = new Task (() => { Thread.Sleep (0); Assert.IsTrue (mre.Wait (3000)); });
158                         tasks[1] = new Task (() => { Assert.IsTrue (mre.Wait (3000)); });
159                         tasks[2] = new Task (() => { Assert.IsTrue (mre.Wait (3000)); });
160
161                         bool ran = false;
162                         Task cont = factory.ContinueWhenAll (tasks, ts => {
163                                 Assert.AreEqual (tasks, ts, "#0");
164                                 ran = true;
165                         });
166
167                         foreach (Task t in tasks)
168                                 t.Start ();
169
170                         mre.Set ();
171
172                         Assert.IsTrue (cont.Wait (1000), "#1");
173                         Assert.IsTrue (ran, "#2");
174                 }
175
176                 [Test]
177                 public void ContinueWhenAll_WithMixedCompletionState ()
178                 {
179                         var mre = new ManualResetEventSlim ();
180                         var task = Task.Factory.StartNew (() => mre.Wait (200));
181                         var contFailed = task.ContinueWith (t => {}, TaskContinuationOptions.OnlyOnFaulted);
182                         var contCanceled = task.ContinueWith (t => {}, TaskContinuationOptions.OnlyOnCanceled);
183                         var contSuccess = task.ContinueWith (t => {}, TaskContinuationOptions.OnlyOnRanToCompletion);
184                         bool ran = false;
185
186                         var cont = Task.Factory.ContinueWhenAll (new Task[] { contFailed, contCanceled, contSuccess }, _ => ran = true);
187
188                         mre.Set ();
189                         cont.Wait (200);
190
191                         Assert.IsTrue (ran);
192                         Assert.AreEqual (TaskStatus.RanToCompletion, cont.Status);
193                 }
194
195                 [Test]
196                 public void ContinueWhenAll_InvalidArguments ()
197                 {
198                         try {
199                                 factory.ContinueWhenAll (null, delegate { });
200                                 Assert.Fail ("#1");
201                         } catch (ArgumentNullException) {
202                         }
203
204                         try {
205                                 factory.ContinueWhenAll (new Task[0], delegate { });
206                                 Assert.Fail ("#2");
207                         } catch (ArgumentException) {
208                         }
209
210                         try {
211                                 factory.ContinueWhenAll (new Task[] { null }, delegate { });
212                                 Assert.Fail ("#3");
213                         } catch (ArgumentException) {
214                         }
215
216                         var tasks = new Task [] {
217                                 factory.StartNew (delegate {})
218                         };
219
220                         try {
221                                 factory.ContinueWhenAll (tasks, null);
222                                 Assert.Fail ("#4");
223                         } catch (ArgumentException) {
224                         }
225
226                         try {
227                                 factory.ContinueWhenAll (tasks, delegate { }, CancellationToken.None, TaskContinuationOptions.None, null);
228                                 Assert.Fail ("#5");
229                         } catch (ArgumentException) {
230                         }
231
232                         try {
233                                 factory.ContinueWhenAll (tasks, delegate { }, CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled, null);
234                                 Assert.Fail ("#6");
235                         } catch (ArgumentException) {
236                         }
237                 }
238
239                 [Test]
240                 public void ContinueWhenAll_WithExceptions ()
241                 {
242                         var t1 = Task.Factory.StartNew (() => { throw new ApplicationException ("Foo"); });
243                         var t2 = Task.Factory.StartNew (() => { throw new ApplicationException ("Bar"); });
244
245                         var cont = Task.Factory.ContinueWhenAll (new[] { t1, t2 }, delegate {});
246                         cont.Wait (200);
247
248                         Assert.IsTrue (t1.IsFaulted);
249                         Assert.IsTrue (t2.IsFaulted);
250                         Assert.AreEqual (TaskStatus.RanToCompletion, cont.Status);
251                 }
252
253                 [Test]
254                 public void ContinueWhenAny_Simple ()
255                 {
256                         var t1 = new ManualResetEvent (false);
257                         var t2 = new ManualResetEvent (false);
258
259                         var tasks = new Task[2] {
260                                 Task.Factory.StartNew (() => { t1.WaitOne (3000); }),
261                                 Task.Factory.StartNew (() => { t2.WaitOne (3000); })
262                         };
263
264                         bool ran = false;
265                         var ct = new CancellationToken ();
266                         Task cont = factory.ContinueWhenAny (tasks, t => {
267                                 Assert.AreEqual (tasks[0], t, "#1");
268                                 ran = true;
269                         }, ct);
270
271                         Assert.AreEqual (TaskStatus.WaitingForActivation, cont.Status, "#2");
272
273                         t1.Set ();
274
275                         Assert.IsTrue (cont.Wait (2000), "#10");
276                         Assert.IsTrue (ran, "#11");
277
278                         t2.Set ();
279                 }
280
281                 [Test]
282                 public void ContinueWhenAny_InvalidArguments ()
283                 {
284                         try {
285                                 factory.ContinueWhenAny (null, delegate { });
286                                 Assert.Fail ("#1");
287                         } catch (ArgumentNullException) {
288                         }
289
290                         try {
291                                 factory.ContinueWhenAny (new Task[0], delegate { });
292                                 Assert.Fail ("#2");
293                         } catch (ArgumentException) {
294                         }
295
296                         try {
297                                 factory.ContinueWhenAny (new Task[] { null }, delegate { });
298                                 Assert.Fail ("#3");
299                         } catch (ArgumentException) {
300                         }
301
302                         var tasks = new Task [] {
303                                 factory.StartNew (delegate {})
304                         };
305
306                         try {
307                                 factory.ContinueWhenAny (tasks, null);
308                                 Assert.Fail ("#4");
309                         } catch (ArgumentException) {
310                         }
311
312                         try {
313                                 factory.ContinueWhenAny (tasks, delegate { }, CancellationToken.None, TaskContinuationOptions.None, null);
314                                 Assert.Fail ("#5");
315                         } catch (ArgumentException) {
316                         }
317
318                         try {
319                                 factory.ContinueWhenAny (tasks, delegate { }, CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled, null);
320                                 Assert.Fail ("#6");
321                         } catch (ArgumentException) {
322                         }
323                 }
324
325                 [Test]
326                 public void FromAsyncBeginInvoke_WithResult ()
327                 {
328                         bool result = false;
329
330                         Func<int, int> func = (i) => {
331                                 Assert.IsTrue (Thread.CurrentThread.IsThreadPoolThread);
332                                 result = true; return i + 3;
333                         };
334
335                         var task = factory.FromAsync<int, int> (func.BeginInvoke, func.EndInvoke, 1, "state", TaskCreationOptions.AttachedToParent);
336                         Assert.IsTrue (task.Wait (5000), "#1");
337                         Assert.IsTrue (result, "#2");
338                         Assert.AreEqual (4, task.Result, "#3");
339                         Assert.AreEqual ("state", (string) task.AsyncState, "#4");
340                         Assert.AreEqual (TaskCreationOptions.AttachedToParent, task.CreationOptions, "#5");
341                 }
342
343                 [Test]
344                 public void FromAsyncBeginMethod_DirectResult ()
345                 {
346                         bool result = false;
347                         bool continuationTest = false;
348
349                         Func<int, int> func = (i) => { result = true; return i + 3; };
350                         Task<int> task = factory.FromAsync<int> (func.BeginInvoke (1, delegate { }, null), func.EndInvoke);
351                         var cont = task.ContinueWith (_ => continuationTest = true, TaskContinuationOptions.ExecuteSynchronously);
352                         task.Wait ();
353                         cont.Wait ();
354
355                         Assert.IsTrue (result);
356                         Assert.IsTrue (continuationTest);
357                         Assert.AreEqual (4, task.Result);
358                 }
359
360                 [Test]
361                 public void FromAsyncBeginMethod_Exception ()
362                 {
363                         bool result = false;
364                         bool continuationTest = false;
365
366                         Func<int, int> func = (i) => { result = true; throw new ApplicationException ("bleh"); };
367                         Task<int> task = factory.FromAsync<int, int> (func.BeginInvoke, func.EndInvoke, 1, null);
368                         var cont = task.ContinueWith (_ => continuationTest = true, TaskContinuationOptions.ExecuteSynchronously);
369                         try {
370                                 task.Wait ();
371                         } catch { }
372                         cont.Wait ();
373
374                         Assert.IsTrue (result);
375                         Assert.IsTrue (continuationTest);
376                         Assert.IsNotNull (task.Exception);
377                         var agg = task.Exception;
378                         Assert.AreEqual (1, agg.InnerExceptions.Count);
379                         Assert.IsInstanceOfType (typeof (ApplicationException), agg.InnerExceptions[0]);
380                         Assert.AreEqual (TaskStatus.Faulted, task.Status);
381
382                         try {
383                                 var a = task.Result;
384                                 Assert.Fail ();
385                         } catch (AggregateException) {
386                         }
387                 }
388
389                 [Test]
390                 public void FromAsync_ArgumentsCheck ()
391                 {
392                         var result = new CompletedAsyncResult ();
393                         try {
394                                 factory.FromAsync (null, l => { });
395                                 Assert.Fail ("#1");
396                         } catch (ArgumentNullException) {
397                         }
398
399                         try {
400                                 factory.FromAsync (result, null);
401                                 Assert.Fail ("#2");
402                         } catch (ArgumentNullException) {
403                         }
404
405                         try {
406                                 factory.FromAsync (result, l => { }, TaskCreationOptions.LongRunning);
407                                 Assert.Fail ("#3");
408                         } catch (ArgumentOutOfRangeException) {
409                         }
410
411                         try {
412                                 factory.FromAsync (result, l => { }, TaskCreationOptions.PreferFairness);
413                                 Assert.Fail ("#4");
414                         } catch (ArgumentOutOfRangeException) {
415                         }
416
417                         try {
418                                 factory.FromAsync (result, l => { }, TaskCreationOptions.None, null);
419                                 Assert.Fail ("#5");
420                         } catch (ArgumentNullException) {
421                         }
422
423                         try {
424                                 factory.FromAsync (null, l => { }, null, TaskCreationOptions.None);
425                                 Assert.Fail ("#6");
426                         } catch (ArgumentNullException) {
427                         }
428
429                         try {
430                                 factory.FromAsync ((a, b) => null, l => { }, null, TaskCreationOptions.LongRunning);
431                                 Assert.Fail ("#7");
432                         } catch (ArgumentOutOfRangeException) {
433                         }
434                 }
435
436                 [Test]
437                 public void FromAsync_Completed ()
438                 {
439                         var completed = new CompletedAsyncResult ();
440                         bool? valid = null;
441
442                         Action<IAsyncResult> end = l => {
443                                 Assert.IsFalse (Thread.CurrentThread.IsThreadPoolThread, "#2");
444                                 valid = l == completed;
445                         };
446                         Task task = factory.FromAsync (completed, end);
447                         Assert.IsTrue (valid == true, "#1");
448                 }
449
450                 [Test]
451                 public void FromAsync_CompletedWithException ()
452                 {
453                         var completed = new CompletedAsyncResult ();
454
455                         Action<IAsyncResult> end = l => {
456                                 throw new ApplicationException ();
457                         };
458                         Task task = factory.FromAsync (completed, end);
459                         Assert.AreEqual (TaskStatus.Faulted, task.Status, "#1");
460                 }
461
462                 [Test]
463                 public void FromAsync_CompletedCanceled ()
464                 {
465                         var completed = new CompletedAsyncResult ();
466
467                         Action<IAsyncResult> end = l => {
468                                 throw new OperationCanceledException ();
469                         };
470                         Task task = factory.FromAsync (completed, end);
471                         Assert.AreEqual (TaskStatus.Canceled, task.Status, "#1");
472                         Assert.IsNull (task.Exception, "#2");
473                 }
474
475                 [Test]
476                 public void FromAsync_SimpleAsyncResult ()
477                 {
478                         var result = new TestAsyncResult ();
479                         bool called = false;
480
481                         var task = factory.FromAsync (result, l => {
482                                 called = true;
483                         });
484
485                         Assert.IsTrue (task.Wait (1000), "#1");
486                         Assert.IsTrue (called, "#2");
487                 }
488
489                 [Test]
490                 public void FromAsync_ResultException ()
491                 {
492                         var result = new TestAsyncResult ();
493
494                         var task = factory.FromAsync (result, l => {
495                                 throw new ApplicationException ();
496                         });
497
498                         try {
499                                 Assert.IsFalse (task.Wait (1000), "#1");
500                         } catch (AggregateException) {
501                         }
502
503                         Assert.AreEqual (TaskStatus.Faulted, task.Status, "#2");
504                 }
505
506                 [Test]
507                 public void FromAsync_ReturnInt ()
508                 {
509                         var result = new TestAsyncResult ();
510                         bool called = false;
511
512                         var task = factory.FromAsync<int> (result, l => {
513                                 called = true;
514                                 return 4;
515                         });
516
517                         Assert.IsTrue (task.Wait (1000), "#1");
518                         Assert.IsTrue (called, "#2");
519                         Assert.AreEqual (4, task.Result, "#3");
520                 }
521
522                 [Test]
523                 public void FromAsync_Scheduler_Explicit ()
524                 {
525                         var result = new TestAsyncResult ();
526                         bool called = false;
527                         var scheduler = new TestScheduler ();
528
529                         var task = factory.FromAsync (result, l => {
530                                 called = true;
531                         }, TaskCreationOptions.None, scheduler);
532
533                         Assert.IsTrue (task.Wait (5000), "#1");
534                         Assert.IsTrue (called, "#2");
535                         Assert.IsTrue (scheduler.ExecutedInline, "#3");
536                 }
537
538                 [Test]
539                 public void FromAsync_Scheduler_Implicit ()
540                 {
541                         var result = new TestAsyncResult ();
542                         bool called = false;
543                         var scheduler = new TestScheduler ();
544
545                         factory = new TaskFactory (scheduler);
546
547                         Task task = factory.FromAsync (result, l => {
548                                 Assert.IsTrue (Thread.CurrentThread.IsThreadPoolThread, "#6");
549                                 called = true;
550                         }, TaskCreationOptions.AttachedToParent);
551
552                         Assert.AreEqual (TaskCreationOptions.AttachedToParent, task.CreationOptions, "#1");
553                         Assert.IsNull (task.AsyncState, "#2");
554                         Assert.IsTrue (task.Wait (5000), "#3");
555                         Assert.IsTrue (called, "#4");
556                         Assert.IsTrue (scheduler.ExecutedInline, "#5");
557                 }
558
559                 [Test]
560                 public void FromAsync_BeginCallback ()
561                 {
562                         bool called = false;
563                         bool called2 = false;
564
565                         var task = factory.FromAsync (
566                                 (a, b, c) => {
567                                         if (a != "h")
568                                                 Assert.Fail ("#10");
569
570                                         if ((TaskCreationOptions) c != TaskCreationOptions.AttachedToParent)
571                                                 Assert.Fail ("#11");
572
573                                         Assert.IsFalse (Thread.CurrentThread.IsThreadPoolThread, "#12");
574
575                                         called2 = true;
576                                         b.Invoke (null);
577                                         return null;
578                                 },
579                                 l => {
580                                         called = true;
581                                 },
582                                 "h", TaskCreationOptions.AttachedToParent);
583
584                         Assert.AreEqual (TaskCreationOptions.None, task.CreationOptions, "#1");
585                         Assert.AreEqual (TaskCreationOptions.AttachedToParent, (TaskCreationOptions) task.AsyncState, "#2");
586                         Assert.IsTrue (task.Wait (5000), "#3");
587                         Assert.IsTrue (called, "#4");
588                         Assert.IsTrue (called2, "#5");
589                 }
590
591                 [Test]
592                 public void StartNewCancelled ()
593                 {
594                         var cts = new CancellationTokenSource ();
595                         cts.Cancel ();
596
597                         var task = factory.StartNew (() => Assert.Fail ("Should never be called"), cts.Token);
598                         try {
599                                 task.Start ();
600                         } catch (InvalidOperationException) {
601                         }
602
603                         Assert.IsTrue (task.IsCanceled, "#2");
604                 }
605         }
606 }
607 #endif