Add unit test for bug #2007
[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 ContinueWhenAny_Simple ()
197                 {
198                         var t1 = new ManualResetEvent (false);
199                         var t2 = new ManualResetEvent (false);
200
201                         var tasks = new Task[2] {
202                                 Task.Factory.StartNew (() => { t1.WaitOne (3000); }),
203                                 Task.Factory.StartNew (() => { t2.WaitOne (3000); })
204                         };
205
206                         bool ran = false;
207                         var ct = new CancellationToken ();
208                         Task cont = factory.ContinueWhenAny (tasks, t => {
209                                 Assert.AreEqual (tasks[0], t, "#1");
210                                 ran = true;
211                         }, ct);
212
213                         Assert.AreEqual (TaskStatus.WaitingForActivation, cont.Status, "#2");
214
215                         t1.Set ();
216
217                         Assert.IsTrue (cont.Wait (2000), "#10");
218                         Assert.IsTrue (ran, "#11");
219
220                         t2.Set ();
221                 }
222
223                 [Test]
224                 public void ContinueWhenAny_InvalidArguments ()
225                 {
226                         try {
227                                 factory.ContinueWhenAny (null, delegate { });
228                                 Assert.Fail ("#1");
229                         } catch (ArgumentNullException) {
230                         }
231
232                         try {
233                                 factory.ContinueWhenAny (new Task[0], delegate { });
234                                 Assert.Fail ("#2");
235                         } catch (ArgumentException) {
236                         }
237
238                         try {
239                                 factory.ContinueWhenAny (new Task[] { null }, delegate { });
240                                 Assert.Fail ("#3");
241                         } catch (ArgumentException) {
242                         }
243
244                         var tasks = new Task [] {
245                                 factory.StartNew (delegate {})
246                         };
247
248                         try {
249                                 factory.ContinueWhenAny (tasks, null);
250                                 Assert.Fail ("#4");
251                         } catch (ArgumentException) {
252                         }
253
254                         try {
255                                 factory.ContinueWhenAny (tasks, delegate { }, CancellationToken.None, TaskContinuationOptions.None, null);
256                                 Assert.Fail ("#5");
257                         } catch (ArgumentException) {
258                         }
259                 }
260
261                 [Test]
262                 public void FromAsyncBeginInvoke_WithResult ()
263                 {
264                         bool result = false;
265
266                         Func<int, int> func = (i) => {
267                                 Assert.IsTrue (Thread.CurrentThread.IsThreadPoolThread);
268                                 result = true; return i + 3;
269                         };
270
271                         var task = factory.FromAsync<int, int> (func.BeginInvoke, func.EndInvoke, 1, "state", TaskCreationOptions.AttachedToParent);
272                         Assert.IsTrue (task.Wait (5000), "#1");
273                         Assert.IsTrue (result, "#2");
274                         Assert.AreEqual (4, task.Result, "#3");
275                         Assert.AreEqual ("state", (string) task.AsyncState, "#4");
276                         Assert.AreEqual (TaskCreationOptions.AttachedToParent, task.CreationOptions, "#5");
277                 }
278
279                 [Test]
280                 public void FromAsyncBeginMethod_DirectResult ()
281                 {
282                         bool result = false;
283                         bool continuationTest = false;
284
285                         Func<int, int> func = (i) => { result = true; return i + 3; };
286                         Task<int> task = factory.FromAsync<int> (func.BeginInvoke (1, delegate { }, null), func.EndInvoke);
287                         var cont = task.ContinueWith (_ => continuationTest = true, TaskContinuationOptions.ExecuteSynchronously);
288                         task.Wait ();
289                         cont.Wait ();
290
291                         Assert.IsTrue (result);
292                         Assert.IsTrue (continuationTest);
293                         Assert.AreEqual (4, task.Result);
294                 }
295
296                 [Test]
297                 public void FromAsyncBeginMethod_Exception ()
298                 {
299                         bool result = false;
300                         bool continuationTest = false;
301
302                         Func<int, int> func = (i) => { result = true; throw new ApplicationException ("bleh"); };
303                         Task<int> task = factory.FromAsync<int, int> (func.BeginInvoke, func.EndInvoke, 1, null);
304                         var cont = task.ContinueWith (_ => continuationTest = true, TaskContinuationOptions.ExecuteSynchronously);
305                         try {
306                                 task.Wait ();
307                         } catch { }
308                         cont.Wait ();
309
310                         Assert.IsTrue (result);
311                         Assert.IsTrue (continuationTest);
312                         Assert.IsNotNull (task.Exception);
313                         var agg = task.Exception;
314                         Assert.AreEqual (1, agg.InnerExceptions.Count);
315                         Assert.IsInstanceOfType (typeof (ApplicationException), agg.InnerExceptions[0]);
316                         Assert.AreEqual (TaskStatus.Faulted, task.Status);
317
318                         try {
319                                 var a = task.Result;
320                                 Assert.Fail ();
321                         } catch (AggregateException) {
322                         }
323                 }
324
325                 [Test]
326                 public void FromAsync_ArgumentsCheck ()
327                 {
328                         var result = new CompletedAsyncResult ();
329                         try {
330                                 factory.FromAsync (null, l => { });
331                                 Assert.Fail ("#1");
332                         } catch (ArgumentNullException) {
333                         }
334
335                         try {
336                                 factory.FromAsync (result, null);
337                                 Assert.Fail ("#2");
338                         } catch (ArgumentNullException) {
339                         }
340
341                         try {
342                                 factory.FromAsync (result, l => { }, TaskCreationOptions.LongRunning);
343                                 Assert.Fail ("#3");
344                         } catch (ArgumentOutOfRangeException) {
345                         }
346
347                         try {
348                                 factory.FromAsync (result, l => { }, TaskCreationOptions.PreferFairness);
349                                 Assert.Fail ("#4");
350                         } catch (ArgumentOutOfRangeException) {
351                         }
352
353                         try {
354                                 factory.FromAsync (result, l => { }, TaskCreationOptions.None, null);
355                                 Assert.Fail ("#5");
356                         } catch (ArgumentNullException) {
357                         }
358
359                         try {
360                                 factory.FromAsync (null, l => { }, null, TaskCreationOptions.None);
361                                 Assert.Fail ("#6");
362                         } catch (ArgumentNullException) {
363                         }
364
365                         try {
366                                 factory.FromAsync ((a, b) => null, l => { }, null, TaskCreationOptions.LongRunning);
367                                 Assert.Fail ("#7");
368                         } catch (ArgumentOutOfRangeException) {
369                         }
370                 }
371
372                 [Test]
373                 public void FromAsync_Completed ()
374                 {
375                         var completed = new CompletedAsyncResult ();
376                         bool? valid = null;
377
378                         Action<IAsyncResult> end = l => {
379                                 Assert.IsFalse (Thread.CurrentThread.IsThreadPoolThread, "#2");
380                                 valid = l == completed;
381                         };
382                         Task task = factory.FromAsync (completed, end);
383                         Assert.IsTrue (valid == true, "#1");
384                 }
385
386                 [Test]
387                 public void FromAsync_CompletedWithException ()
388                 {
389                         var completed = new CompletedAsyncResult ();
390
391                         Action<IAsyncResult> end = l => {
392                                 throw new ApplicationException ();
393                         };
394                         Task task = factory.FromAsync (completed, end);
395                         Assert.AreEqual (TaskStatus.Faulted, task.Status, "#1");
396                 }
397
398                 [Test]
399                 public void FromAsync_CompletedCanceled ()
400                 {
401                         var completed = new CompletedAsyncResult ();
402
403                         Action<IAsyncResult> end = l => {
404                                 throw new OperationCanceledException ();
405                         };
406                         Task task = factory.FromAsync (completed, end);
407                         Assert.AreEqual (TaskStatus.Canceled, task.Status, "#1");
408                         Assert.IsNull (task.Exception, "#2");
409                 }
410
411                 [Test]
412                 public void FromAsync_SimpleAsyncResult ()
413                 {
414                         var result = new TestAsyncResult ();
415                         bool called = false;
416
417                         var task = factory.FromAsync (result, l => {
418                                 called = true;
419                         });
420
421                         Assert.IsTrue (task.Wait (1000), "#1");
422                         Assert.IsTrue (called, "#2");
423                 }
424
425                 [Test]
426                 public void FromAsync_ResultException ()
427                 {
428                         var result = new TestAsyncResult ();
429
430                         var task = factory.FromAsync (result, l => {
431                                 throw new ApplicationException ();
432                         });
433
434                         try {
435                                 Assert.IsFalse (task.Wait (1000), "#1");
436                         } catch (AggregateException) {
437                         }
438
439                         Assert.AreEqual (TaskStatus.Faulted, task.Status, "#2");
440                 }
441
442                 [Test]
443                 public void FromAsync_ReturnInt ()
444                 {
445                         var result = new TestAsyncResult ();
446                         bool called = false;
447
448                         var task = factory.FromAsync<int> (result, l => {
449                                 called = true;
450                                 return 4;
451                         });
452
453                         Assert.IsTrue (task.Wait (1000), "#1");
454                         Assert.IsTrue (called, "#2");
455                         Assert.AreEqual (4, task.Result, "#3");
456                 }
457
458                 [Test]
459                 public void FromAsync_Scheduler_Explicit ()
460                 {
461                         var result = new TestAsyncResult ();
462                         bool called = false;
463                         var scheduler = new TestScheduler ();
464
465                         var task = factory.FromAsync (result, l => {
466                                 called = true;
467                         }, TaskCreationOptions.None, scheduler);
468
469                         Assert.IsTrue (task.Wait (5000), "#1");
470                         Assert.IsTrue (called, "#2");
471                         Assert.IsTrue (scheduler.ExecutedInline, "#3");
472                 }
473
474                 [Test]
475                 public void FromAsync_Scheduler_Implicit ()
476                 {
477                         var result = new TestAsyncResult ();
478                         bool called = false;
479                         var scheduler = new TestScheduler ();
480
481                         factory = new TaskFactory (scheduler);
482
483                         Task task = factory.FromAsync (result, l => {
484                                 Assert.IsTrue (Thread.CurrentThread.IsThreadPoolThread, "#6");
485                                 called = true;
486                         }, TaskCreationOptions.AttachedToParent);
487
488                         Assert.AreEqual (TaskCreationOptions.AttachedToParent, task.CreationOptions, "#1");
489                         Assert.IsNull (task.AsyncState, "#2");
490                         Assert.IsTrue (task.Wait (5000), "#3");
491                         Assert.IsTrue (called, "#4");
492                         Assert.IsTrue (scheduler.ExecutedInline, "#5");
493                 }
494
495                 [Test]
496                 public void FromAsync_BeginCallback ()
497                 {
498                         bool called = false;
499                         bool called2 = false;
500
501                         var task = factory.FromAsync (
502                                 (a, b, c) => {
503                                         if (a != "h")
504                                                 Assert.Fail ("#10");
505
506                                         if ((TaskCreationOptions) c != TaskCreationOptions.AttachedToParent)
507                                                 Assert.Fail ("#11");
508
509                                         Assert.IsFalse (Thread.CurrentThread.IsThreadPoolThread, "#12");
510
511                                         called2 = true;
512                                         b.Invoke (null);
513                                         return null;
514                                 },
515                                 l => {
516                                         called = true;
517                                 },
518                                 "h", TaskCreationOptions.AttachedToParent);
519
520                         Assert.AreEqual (TaskCreationOptions.None, task.CreationOptions, "#1");
521                         Assert.AreEqual (TaskCreationOptions.AttachedToParent, (TaskCreationOptions) task.AsyncState, "#2");
522                         Assert.IsTrue (task.Wait (5000), "#3");
523                         Assert.IsTrue (called, "#4");
524                         Assert.IsTrue (called2, "#5");
525                 }
526
527                 [Test]
528                 public void StartNewCancelled ()
529                 {
530                         var cts = new CancellationTokenSource ();
531                         cts.Cancel ();
532
533                         var task = factory.StartNew (() => Assert.Fail ("Should never be called"), cts.Token);
534                         try {
535                                 task.Start ();
536                         } catch (InvalidOperationException) {
537                         }
538
539                         Assert.IsTrue (task.IsCanceled, "#2");
540                 }
541         }
542 }
543 #endif