Merge pull request #1936 from esdrubal/DotNetRelativeOrAbsolute
[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
32 using System;
33 using System.Threading;
34 using System.Threading.Tasks;
35 using System.Collections.Generic;
36
37 using NUnit.Framework;
38 #if !MOBILE
39 using NUnit.Framework.SyntaxHelpers;
40 #endif
41
42 namespace MonoTests.System.Threading.Tasks
43 {
44         [TestFixture]
45         public class TaskFactoryTests
46         {
47                 class CompletedAsyncResult : IAsyncResult
48                 {
49                         public object AsyncState
50                         {
51                                 get { throw new NotImplementedException (); }
52                         }
53
54                         public WaitHandle AsyncWaitHandle
55                         {
56                                 get { throw new NotImplementedException (); }
57                         }
58
59                         public bool CompletedSynchronously
60                         {
61                                 get { throw new NotImplementedException (); }
62                         }
63
64                         public bool IsCompleted
65                         {
66                                 get { return true; }
67                         }
68                 }
69
70                 class TestAsyncResult : IAsyncResult
71                 {
72                         WaitHandle wh = new ManualResetEvent (true);
73
74                         public object AsyncState
75                         {
76                                 get { throw new NotImplementedException (); }
77                         }
78
79                         public WaitHandle AsyncWaitHandle
80                         {
81                                 get
82                                 {
83                                         return wh;
84                                 }
85                         }
86
87                         public bool CompletedSynchronously
88                         {
89                                 get { throw new NotImplementedException (); }
90                         }
91
92                         public bool IsCompleted
93                         {
94                                 get { return false; }
95                         }
96                 }
97
98                 class TestScheduler : TaskScheduler
99                 {
100                         public bool ExecutedInline { get; set; }
101
102                         protected override void QueueTask (Task task)
103                         {
104                                 throw new NotImplementedException ();
105                         }
106
107                         protected override bool TryDequeue (Task task)
108                         {
109                                 throw new NotImplementedException ();
110                         }
111
112                         protected override bool TryExecuteTaskInline (Task task, bool taskWasPreviouslyQueued)
113                         {
114                                 if (taskWasPreviouslyQueued)
115                                         throw new ArgumentException ("taskWasPreviouslyQueued");
116
117                                 if (task.Status != TaskStatus.WaitingToRun)
118                                         throw new ArgumentException ("task.Status");
119
120                                 ExecutedInline = true;
121                                 return TryExecuteTask (task);
122                         }
123
124                         protected override IEnumerable<Task> GetScheduledTasks ()
125                         {
126                                 throw new NotImplementedException ();
127                         }
128                 }
129
130
131                 TaskFactory factory;
132
133                 [SetUp]
134                 public void Setup ()
135                 {
136                         this.factory = Task.Factory;
137                 }
138
139                 [Test]
140                 public void StartNewTest ()
141                 {
142                         bool result = false;
143                         factory.StartNew (() => result = true).Wait ();
144                         Assert.IsTrue (result);
145                 }
146
147                 [Test]
148                 public void NoDefaultScheduler ()
149                 {
150                         Assert.IsNull (factory.Scheduler, "#1");
151                 }
152
153                 [Test]
154                 public void ContinueWhenAll_Simple ()
155                 {
156                         var mre = new ManualResetEventSlim (false);
157
158                         Task[] tasks = new Task[3];
159                         tasks[0] = new Task (() => { Thread.Sleep (0); Assert.IsTrue (mre.Wait (5000)); });
160                         tasks[1] = new Task (() => { Assert.IsTrue (mre.Wait (5000)); });
161                         tasks[2] = new Task (() => { Assert.IsTrue (mre.Wait (5000)); });
162
163                         bool ran = false;
164                         Task cont = factory.ContinueWhenAll (tasks, ts => {
165                                 Assert.AreEqual (tasks, ts, "#0");
166                                 ran = true;
167                         });
168
169                         foreach (Task t in tasks)
170                                 t.Start ();
171
172                         mre.Set ();
173
174                         Assert.IsTrue (cont.Wait (3000), "#1");
175                         Assert.IsTrue (ran, "#2");
176                 }
177
178                 [Test]
179                 public void ContinueWhenAll_WithMixedCompletionState ()
180                 {
181                         var mre = new ManualResetEventSlim ();
182                         var task = Task.Factory.StartNew (() => mre.Wait (1000));
183                         var contFailed = task.ContinueWith (t => {}, TaskContinuationOptions.OnlyOnFaulted);
184                         var contCanceled = task.ContinueWith (t => {}, TaskContinuationOptions.OnlyOnCanceled);
185                         var contSuccess = task.ContinueWith (t => {}, TaskContinuationOptions.OnlyOnRanToCompletion);
186                         bool ran = false;
187
188                         var cont = Task.Factory.ContinueWhenAll (new Task[] { contFailed, contCanceled, contSuccess }, _ => ran = true);
189
190                         mre.Set ();
191                         cont.Wait (3000);
192
193                         Assert.IsTrue (ran);
194                         Assert.AreEqual (TaskStatus.RanToCompletion, cont.Status);
195                 }
196
197                 [Test]
198                 public void ContinueWhenAll_InvalidArguments ()
199                 {
200                         try {
201                                 factory.ContinueWhenAll (null, delegate { });
202                                 Assert.Fail ("#1");
203                         } catch (ArgumentNullException) {
204                         }
205
206                         try {
207                                 factory.ContinueWhenAll (new Task[0], delegate { });
208                                 Assert.Fail ("#2");
209                         } catch (ArgumentException) {
210                         }
211
212                         try {
213                                 factory.ContinueWhenAll (new Task[] { null }, delegate { });
214                                 Assert.Fail ("#3");
215                         } catch (ArgumentException) {
216                         }
217
218                         var tasks = new Task [] {
219                                 factory.StartNew (delegate {})
220                         };
221
222                         try {
223                                 factory.ContinueWhenAll (tasks, null);
224                                 Assert.Fail ("#4");
225                         } catch (ArgumentNullException) {
226                         }
227
228                         try {
229                                 factory.ContinueWhenAll (tasks, delegate { }, CancellationToken.None, TaskContinuationOptions.None, null);
230                                 Assert.Fail ("#5");
231                         } catch (ArgumentNullException) {
232                         }
233
234                         try {
235                                 factory.ContinueWhenAll (tasks, delegate { }, CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled, null);
236                                 Assert.Fail ("#6");
237                         } catch (ArgumentNullException) {
238                         } catch (ArgumentOutOfRangeException) {
239                         }
240                 }
241
242                 [Test]
243                 public void ContinueWhenAll_WithExceptions ()
244                 {
245                         var t1 = Task.Factory.StartNew (() => { throw new ApplicationException ("Foo"); });
246                         var t2 = Task.Factory.StartNew (() => { throw new ApplicationException ("Bar"); });
247
248                         var cont = Task.Factory.ContinueWhenAll (new[] { t1, t2 }, delegate {});
249                         cont.Wait (200);
250
251                         Assert.IsTrue (t1.IsFaulted);
252                         Assert.IsTrue (t2.IsFaulted);
253                         Assert.AreEqual (TaskStatus.RanToCompletion, cont.Status);
254                 }
255
256                 [Test]
257                 public void ContinueWhenAny_Simple ()
258                 {
259                         var t1 = new ManualResetEvent (false);
260                         var t2 = new ManualResetEvent (false);
261
262                         var tasks = new Task[2] {
263                                 Task.Factory.StartNew (() => { t1.WaitOne (5000); }),
264                                 Task.Factory.StartNew (() => { t2.WaitOne (5000); })
265                         };
266
267                         bool ran = false;
268                         var ct = new CancellationToken ();
269                         Task cont = factory.ContinueWhenAny (tasks, t => {
270                                 Assert.AreEqual (tasks[0], t, "#1");
271                                 ran = true;
272                         }, ct);
273
274                         Assert.AreEqual (TaskStatus.WaitingForActivation, cont.Status, "#2");
275
276                         t1.Set ();
277
278                         Assert.IsTrue (cont.Wait (3000), "#10");
279                         Assert.IsTrue (ran, "#11");
280
281                         t2.Set ();
282                 }
283
284                 [Test]
285                 public void ContinueWhenAny_WithResult ()
286                 {
287                         var tcs = new TaskCompletionSource<int>();
288                         tcs.SetResult(1);
289                         Task[] tasks = new[] { tcs.Task };
290                         var res = Task.Factory.ContinueWhenAny (tasks, l => 4);
291                         Assert.AreEqual (4, res.Result);
292                 }
293
294                 [Test]
295                 public void ContinueWhenAny_InvalidArguments ()
296                 {
297                         try {
298                                 factory.ContinueWhenAny (null, delegate { });
299                                 Assert.Fail ("#1");
300                         } catch (ArgumentNullException) {
301                         }
302
303                         try {
304                                 factory.ContinueWhenAny (new Task[0], delegate { });
305                                 Assert.Fail ("#2");
306                         } catch (ArgumentException) {
307                         }
308
309                         try {
310                                 factory.ContinueWhenAny (new Task[] { null }, delegate { });
311                                 Assert.Fail ("#3");
312                         } catch (ArgumentException) {
313                         }
314
315                         var tasks = new Task [] {
316                                 factory.StartNew (delegate {})
317                         };
318
319                         try {
320                                 factory.ContinueWhenAny (tasks, null);
321                                 Assert.Fail ("#4");
322                         } catch (ArgumentNullException) {
323                         }
324
325                         try {
326                                 factory.ContinueWhenAny (tasks, delegate { }, CancellationToken.None, TaskContinuationOptions.None, null);
327                                 Assert.Fail ("#5");
328                         } catch (ArgumentNullException) {
329                         }
330
331                         try {
332                                 factory.ContinueWhenAny (tasks, delegate { }, CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled, null);
333                                 Assert.Fail ("#6");
334                         } catch (ArgumentNullException) {
335                         } catch (ArgumentOutOfRangeException) {
336                         }
337                 }
338
339                 [Test]
340                 public void FromAsyncBeginInvoke_WithResult ()
341                 {
342                         bool result = false;
343
344                         Func<int, int> func = (i) => {
345                                 Assert.IsTrue (Thread.CurrentThread.IsThreadPoolThread);
346                                 result = true; return i + 3;
347                         };
348
349                         var task = factory.FromAsync<int, int> (func.BeginInvoke, func.EndInvoke, 1, "state", TaskCreationOptions.AttachedToParent);
350                         Assert.IsTrue (task.Wait (5000), "#1");
351                         Assert.IsTrue (result, "#2");
352                         Assert.AreEqual (4, task.Result, "#3");
353                         Assert.AreEqual ("state", (string) task.AsyncState, "#4");
354                         Assert.AreEqual (TaskCreationOptions.AttachedToParent, task.CreationOptions, "#5");
355                 }
356
357                 [Test]
358                 public void FromAsyncBeginMethod_DirectResult ()
359                 {
360                         bool result = false;
361                         bool continuationTest = false;
362
363                         Func<int, int> func = (i) => { result = true; return i + 3; };
364                         Task<int> task = factory.FromAsync<int> (func.BeginInvoke (1, delegate { }, null), func.EndInvoke);
365                         var cont = task.ContinueWith (_ => continuationTest = true, TaskContinuationOptions.ExecuteSynchronously);
366                         task.Wait ();
367                         cont.Wait ();
368
369                         Assert.IsTrue (result);
370                         Assert.IsTrue (continuationTest);
371                         Assert.AreEqual (4, task.Result);
372                 }
373
374                 [Test]
375                 public void FromAsyncBeginMethod_Exception ()
376                 {
377                         bool result = false;
378                         bool continuationTest = false;
379
380                         Func<int, int> func = (i) => { result = true; throw new ApplicationException ("bleh"); };
381                         Task<int> task = factory.FromAsync<int, int> (func.BeginInvoke, func.EndInvoke, 1, null);
382                         var cont = task.ContinueWith (_ => continuationTest = true, TaskContinuationOptions.ExecuteSynchronously);
383                         try {
384                                 task.Wait (2000);
385                         } catch { }
386                         Assert.IsTrue (cont.Wait (2000), "#1");
387
388                         Assert.IsTrue (result);
389                         Assert.IsTrue (continuationTest);
390                         Assert.IsNotNull (task.Exception);
391                         var agg = task.Exception;
392                         Assert.AreEqual (1, agg.InnerExceptions.Count);
393                         Assert.That (agg.InnerExceptions[0], Is.TypeOf (typeof (ApplicationException)));
394                         Assert.AreEqual (TaskStatus.Faulted, task.Status);
395
396                         try {
397                                 var a = task.Result;
398                                 Assert.Fail ();
399                         } catch (AggregateException) {
400                         }
401                 }
402
403                 [Test]
404                 public void FromAsync_ArgumentsCheck ()
405                 {
406                         var result = new CompletedAsyncResult ();
407                         try {
408                                 factory.FromAsync (null, l => { });
409                                 Assert.Fail ("#1");
410                         } catch (ArgumentNullException) {
411                         }
412
413                         try {
414                                 factory.FromAsync (result, null);
415                                 Assert.Fail ("#2");
416                         } catch (ArgumentNullException) {
417                         }
418
419                         try {
420                                 factory.FromAsync (result, l => { }, TaskCreationOptions.LongRunning);
421                                 Assert.Fail ("#3");
422                         } catch (ArgumentOutOfRangeException) {
423                         }
424
425                         try {
426                                 factory.FromAsync (result, l => { }, TaskCreationOptions.PreferFairness);
427                                 Assert.Fail ("#4");
428                         } catch (ArgumentOutOfRangeException) {
429                         }
430
431                         try {
432                                 factory.FromAsync (result, l => { }, TaskCreationOptions.None, null);
433                                 Assert.Fail ("#5");
434                         } catch (ArgumentNullException) {
435                         }
436
437                         try {
438                                 factory.FromAsync (null, l => { }, null, TaskCreationOptions.None);
439                                 Assert.Fail ("#6");
440                         } catch (ArgumentNullException) {
441                         }
442
443                         try {
444                                 factory.FromAsync ((a, b) => null, l => { }, null, TaskCreationOptions.LongRunning);
445                                 Assert.Fail ("#7");
446                         } catch (ArgumentOutOfRangeException) {
447                         }
448                 }
449
450                 [Test]
451                 public void FromAsync_Completed ()
452                 {
453                         var completed = new CompletedAsyncResult ();
454                         bool? valid = null;
455
456                         Action<IAsyncResult> end = l => {
457                                 Assert.IsFalse (Thread.CurrentThread.IsThreadPoolThread, "#2");
458                                 valid = l == completed;
459                         };
460                         Task task = factory.FromAsync (completed, end);
461                         Assert.IsTrue (valid == true, "#1");
462                 }
463
464                 [Test]
465                 public void FromAsync_CompletedWithException ()
466                 {
467                         var completed = new CompletedAsyncResult ();
468
469                         Action<IAsyncResult> end = l => {
470                                 throw new ApplicationException ();
471                         };
472                         Task task = factory.FromAsync (completed, end);
473                         Assert.AreEqual (TaskStatus.Faulted, task.Status, "#1");
474                 }
475
476                 [Test]
477                 public void FromAsync_CompletedCanceled ()
478                 {
479                         var completed = new CompletedAsyncResult ();
480
481                         Action<IAsyncResult> end = l => {
482                                 throw new OperationCanceledException ();
483                         };
484                         Task task = factory.FromAsync (completed, end);
485                         Assert.AreEqual (TaskStatus.Canceled, task.Status, "#1");
486                         Assert.IsNull (task.Exception, "#2");
487                 }
488
489                 [Test]
490                 public void FromAsync_SimpleAsyncResult ()
491                 {
492                         var result = new TestAsyncResult ();
493                         bool called = false;
494
495                         var task = factory.FromAsync (result, l => {
496                                 called = true;
497                         });
498
499                         Assert.IsTrue (task.Wait (1000), "#1");
500                         Assert.IsTrue (called, "#2");
501                 }
502
503                 [Test]
504                 public void FromAsync_ResultException ()
505                 {
506                         var result = new TestAsyncResult ();
507
508                         var task = factory.FromAsync (result, l => {
509                                 throw new ApplicationException ();
510                         });
511
512                         try {
513                                 Assert.IsFalse (task.Wait (1000), "#1");
514                         } catch (AggregateException) {
515                         }
516
517                         Assert.AreEqual (TaskStatus.Faulted, task.Status, "#2");
518                 }
519
520                 [Test]
521                 public void FromAsync_ReturnInt ()
522                 {
523                         var result = new TestAsyncResult ();
524                         bool called = false;
525
526                         var task = factory.FromAsync<int> (result, l => {
527                                 called = true;
528                                 return 4;
529                         });
530
531                         Assert.IsTrue (task.Wait (1000), "#1");
532                         Assert.IsTrue (called, "#2");
533                         Assert.AreEqual (4, task.Result, "#3");
534                 }
535
536                 [Test]
537                 public void FromAsync_Scheduler_Explicit ()
538                 {
539                         var result = new TestAsyncResult ();
540                         bool called = false;
541                         var scheduler = new TestScheduler ();
542
543                         var task = factory.FromAsync (result, l => {
544                                 called = true;
545                         }, TaskCreationOptions.None, scheduler);
546
547                         Assert.IsTrue (task.Wait (5000), "#1");
548                         Assert.IsTrue (called, "#2");
549                         Assert.IsTrue (scheduler.ExecutedInline, "#3");
550                 }
551
552                 [Test]
553                 public void FromAsync_Scheduler_Implicit ()
554                 {
555                         var result = new TestAsyncResult ();
556                         bool called = false;
557                         var scheduler = new TestScheduler ();
558
559                         factory = new TaskFactory (scheduler);
560
561                         Task task = factory.FromAsync (result, l => {
562                                 Assert.IsTrue (Thread.CurrentThread.IsThreadPoolThread, "#6");
563                                 called = true;
564                         }, TaskCreationOptions.AttachedToParent);
565
566                         Assert.AreEqual (TaskCreationOptions.AttachedToParent, task.CreationOptions, "#1");
567                         Assert.IsNull (task.AsyncState, "#2");
568                         Assert.IsTrue (task.Wait (5000), "#3");
569                         Assert.IsTrue (called, "#4");
570                         Assert.IsTrue (scheduler.ExecutedInline, "#5");
571                 }
572
573                 [Test]
574                 public void FromAsync_BeginCallback ()
575                 {
576                         bool called = false;
577                         bool called2 = false;
578
579                         var task = factory.FromAsync (
580                                 (a, b, c) => {
581                                         if (a != "h")
582                                                 Assert.Fail ("#10");
583
584                                         if ((TaskCreationOptions) c != TaskCreationOptions.AttachedToParent)
585                                                 Assert.Fail ("#11");
586
587                                         Assert.IsFalse (Thread.CurrentThread.IsThreadPoolThread, "#12");
588
589                                         called2 = true;
590                                         b.Invoke (null);
591                                         return null;
592                                 },
593                                 l => {
594                                         called = true;
595                                 },
596                                 "h", TaskCreationOptions.AttachedToParent);
597
598                         Assert.AreEqual (TaskCreationOptions.None, task.CreationOptions, "#1");
599                         Assert.AreEqual (TaskCreationOptions.AttachedToParent, (TaskCreationOptions) task.AsyncState, "#2");
600                         Assert.IsTrue (task.Wait (5000), "#3");
601                         Assert.IsTrue (called, "#4");
602                         Assert.IsTrue (called2, "#5");
603                 }
604
605                 [Test]
606                 public void StartNewCancelled ()
607                 {
608                         var ct = new CancellationToken (true);
609
610                         var task = factory.StartNew (() => Assert.Fail ("Should never be called"), ct);
611                         try {
612                                 task.Start ();
613                                 Assert.Fail ("#1");
614                         } catch (InvalidOperationException) {
615                         }
616
617                         try {
618                                 task.Wait ();
619                                 Assert.Fail ("#2");
620                         } catch (AggregateException e) {
621                                 Assert.That (e.InnerException, Is.TypeOf (typeof (TaskCanceledException)), "#3");
622                         }
623
624                         Assert.IsTrue (task.IsCanceled, "#4");
625                 }
626         }
627 }