31c4ad5da512ac1fdac7bf6fb06b12dd60c3a4de
[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 ContinueWhenAllTest ()
153                 {
154                         bool r1 = false, r2 = false, r3 = false;
155
156                         Task[] tasks = new Task[3];
157                         tasks[0] = new Task (() => { Thread.Sleep (100); r1 = true; });
158                         tasks[1] = new Task (() => { Thread.Sleep (500); r2 = true; });
159                         tasks[2] = new Task (() => { Thread.Sleep (300); r3 = true; });
160
161                         bool result = false;
162
163                         Task cont = factory.ContinueWhenAll (tasks, (ts) => { if (r1 && r2 && r3) result = true; });
164
165                         foreach (Task t in tasks)
166                                 t.Start ();
167
168                         Assert.IsTrue (cont.Wait (1000), "#0");
169
170                         Assert.IsTrue (r1, "#1");
171                         Assert.IsTrue (r2, "#2");
172                         Assert.IsTrue (r3, "#3");
173                         Assert.IsTrue (result, "#4");
174                 }
175
176                 [Test]
177                 public void ContinueWhenAnyTest ()
178                 {
179                         bool r = false, result = false, finished = false;
180
181                         Task[] tasks = new Task[2];
182                         tasks[0] = new Task (() => { Thread.Sleep (300); r = true; });
183                         tasks[1] = new Task (() => { SpinWait sw = new SpinWait (); while (!finished) sw.SpinOnce (); });
184                         //tasks[2] = new Task (() => { SpinWait sw; while (!finished) sw.SpinOnce (); });
185
186                         Task cont = factory.ContinueWhenAny (tasks, (t) => { if (r) result = t == tasks[0]; finished = true; });
187
188                         foreach (Task t in tasks)
189                                 t.Start ();
190
191                         Assert.IsTrue (cont.Wait (2000), "#0");
192
193                         Assert.IsTrue (r, "#1");
194                         Assert.IsTrue (result, "#2");
195                         Assert.IsTrue (finished, "#3");
196                 }
197
198                 [Test]
199                 public void FromAsyncBeginInvoke_WithResult ()
200                 {
201                         bool result = false;
202
203                         Func<int, int> func = (i) => {
204                                 Assert.IsTrue (Thread.CurrentThread.IsThreadPoolThread);
205                                 result = true; return i + 3;
206                         };
207
208                         var task = factory.FromAsync<int, int> (func.BeginInvoke, func.EndInvoke, 1, "state", TaskCreationOptions.AttachedToParent);
209                         Assert.IsTrue (task.Wait (5000), "#1");
210                         Assert.IsTrue (result, "#2");
211                         Assert.AreEqual (4, task.Result, "#3");
212                         Assert.AreEqual ("state", (string) task.AsyncState, "#4");
213                         Assert.AreEqual (TaskCreationOptions.AttachedToParent, task.CreationOptions, "#5");
214                 }
215
216                 [Test]
217                 public void FromAsyncBeginMethod_DirectResult ()
218                 {
219                         bool result = false;
220                         bool continuationTest = false;
221
222                         Func<int, int> func = (i) => { result = true; return i + 3; };
223                         Task<int> task = factory.FromAsync<int> (func.BeginInvoke (1, delegate { }, null), func.EndInvoke);
224                         var cont = task.ContinueWith (_ => continuationTest = true, TaskContinuationOptions.ExecuteSynchronously);
225                         task.Wait ();
226                         cont.Wait ();
227
228                         Assert.IsTrue (result);
229                         Assert.IsTrue (continuationTest);
230                         Assert.AreEqual (4, task.Result);
231                 }
232
233                 [Test]
234                 public void FromAsyncBeginMethod_Exception ()
235                 {
236                         bool result = false;
237                         bool continuationTest = false;
238
239                         Func<int, int> func = (i) => { result = true; throw new ApplicationException ("bleh"); return i + 3; };
240                         Task<int> task = factory.FromAsync<int, int> (func.BeginInvoke, func.EndInvoke, 1, null);
241                         var cont = task.ContinueWith (_ => continuationTest = true, TaskContinuationOptions.ExecuteSynchronously);
242                         try {
243                                 task.Wait ();
244                         } catch { }
245                         cont.Wait ();
246
247                         Assert.IsTrue (result);
248                         Assert.IsTrue (continuationTest);
249                         Assert.IsNotNull (task.Exception);
250                         var agg = task.Exception;
251                         Assert.AreEqual (1, agg.InnerExceptions.Count);
252                         Assert.IsInstanceOfType (typeof (ApplicationException), agg.InnerExceptions[0]);
253                         Assert.AreEqual (TaskStatus.Faulted, task.Status);
254
255                         try {
256                                 var a = task.Result;
257                                 Assert.Fail ();
258                         } catch (AggregateException) {
259                         }
260                 }
261
262                 [Test]
263                 public void FromAsync_ArgumentsCheck ()
264                 {
265                         var result = new CompletedAsyncResult ();
266                         try {
267                                 factory.FromAsync (null, l => { });
268                                 Assert.Fail ("#1");
269                         } catch (ArgumentNullException) {
270                         }
271
272                         try {
273                                 factory.FromAsync (result, null);
274                                 Assert.Fail ("#2");
275                         } catch (ArgumentNullException) {
276                         }
277
278                         try {
279                                 factory.FromAsync (result, l => { }, TaskCreationOptions.LongRunning);
280                                 Assert.Fail ("#3");
281                         } catch (ArgumentOutOfRangeException) {
282                         }
283
284                         try {
285                                 factory.FromAsync (result, l => { }, TaskCreationOptions.PreferFairness);
286                                 Assert.Fail ("#4");
287                         } catch (ArgumentOutOfRangeException) {
288                         }
289
290                         try {
291                                 factory.FromAsync (result, l => { }, TaskCreationOptions.None, null);
292                                 Assert.Fail ("#5");
293                         } catch (ArgumentNullException) {
294                         }
295
296                         try {
297                                 factory.FromAsync (null, l => { }, null, TaskCreationOptions.None);
298                                 Assert.Fail ("#6");
299                         } catch (ArgumentNullException) {
300                         }
301
302                         try {
303                                 factory.FromAsync ((a, b) => null, l => { }, null, TaskCreationOptions.LongRunning);
304                                 Assert.Fail ("#7");
305                         } catch (ArgumentOutOfRangeException) {
306                         }
307                 }
308
309                 [Test]
310                 public void FromAsync_Completed ()
311                 {
312                         var completed = new CompletedAsyncResult ();
313                         bool? valid = null;
314
315                         Action<IAsyncResult> end = l => {
316                                 Assert.IsFalse (Thread.CurrentThread.IsThreadPoolThread, "#2");
317                                 valid = l == completed;
318                         };
319                         Task task = factory.FromAsync (completed, end);
320                         Assert.IsTrue (valid == true, "#1");
321                 }
322
323                 [Test]
324                 public void FromAsync_CompletedWithException ()
325                 {
326                         var completed = new CompletedAsyncResult ();
327
328                         Action<IAsyncResult> end = l => {
329                                 throw new ApplicationException ();
330                         };
331                         Task task = factory.FromAsync (completed, end);
332                         Assert.AreEqual (TaskStatus.Faulted, task.Status, "#1");
333                 }
334
335                 [Test]
336                 public void FromAsync_CompletedCanceled ()
337                 {
338                         var completed = new CompletedAsyncResult ();
339
340                         Action<IAsyncResult> end = l => {
341                                 throw new OperationCanceledException ();
342                         };
343                         Task task = factory.FromAsync (completed, end);
344                         Assert.AreEqual (TaskStatus.Canceled, task.Status, "#1");
345                         Assert.IsNull (task.Exception, "#2");
346                 }
347
348                 [Test]
349                 public void FromAsync_SimpleAsyncResult ()
350                 {
351                         var result = new TestAsyncResult ();
352                         bool called = false;
353
354                         var task = factory.FromAsync (result, l => {
355                                 called = true;
356                         });
357
358                         Assert.IsTrue (task.Wait (1000), "#1");
359                         Assert.IsTrue (called, "#2");
360                 }
361
362                 [Test]
363                 public void FromAsync_ResultException ()
364                 {
365                         var result = new TestAsyncResult ();
366
367                         var task = factory.FromAsync (result, l => {
368                                 throw new ApplicationException ();
369                         });
370
371                         try {
372                                 Assert.IsFalse (task.Wait (1000), "#1");
373                         } catch (AggregateException) {
374                         }
375
376                         Assert.AreEqual (TaskStatus.Faulted, task.Status, "#2");
377                 }
378
379                 [Test]
380                 public void FromAsync_ReturnInt ()
381                 {
382                         var result = new TestAsyncResult ();
383                         bool called = false;
384
385                         var task = factory.FromAsync<int> (result, l => {
386                                 called = true;
387                                 return 4;
388                         });
389
390                         Assert.IsTrue (task.Wait (1000), "#1");
391                         Assert.IsTrue (called, "#2");
392                         Assert.AreEqual (4, task.Result, "#3");
393                 }
394
395                 [Test]
396                 public void FromAsync_Scheduler_Explicit ()
397                 {
398                         var result = new TestAsyncResult ();
399                         bool called = false;
400                         var scheduler = new TestScheduler ();
401
402                         var task = factory.FromAsync (result, l => {
403                                 called = true;
404                         }, TaskCreationOptions.None, scheduler);
405
406                         Assert.IsTrue (task.Wait (5000), "#1");
407                         Assert.IsTrue (called, "#2");
408                         Assert.IsTrue (scheduler.ExecutedInline, "#3");
409                 }
410
411                 [Test]
412                 public void FromAsync_Scheduler_Implicit ()
413                 {
414                         var result = new TestAsyncResult ();
415                         bool called = false;
416                         var scheduler = new TestScheduler ();
417
418                         factory = new TaskFactory (scheduler);
419
420                         Task task = factory.FromAsync (result, l => {
421                                 Assert.IsTrue (Thread.CurrentThread.IsThreadPoolThread, "#6");
422                                 called = true;
423                         }, TaskCreationOptions.AttachedToParent);
424
425                         Assert.AreEqual (TaskCreationOptions.AttachedToParent, task.CreationOptions, "#1");
426                         Assert.IsNull (task.AsyncState, "#2");
427                         Assert.IsTrue (task.Wait (5000), "#3");
428                         Assert.IsTrue (called, "#4");
429                         Assert.IsTrue (scheduler.ExecutedInline, "#5");
430                 }
431
432                 [Test]
433                 public void FromAsync_BeginCallback ()
434                 {
435                         bool called = false;
436                         bool called2 = false;
437
438                         var task = factory.FromAsync (
439                                 (a, b, c) => {
440                                         if (a != "h")
441                                                 Assert.Fail ("#10");
442
443                                         if ((TaskCreationOptions) c != TaskCreationOptions.AttachedToParent)
444                                                 Assert.Fail ("#11");
445
446                                         Assert.IsFalse (Thread.CurrentThread.IsThreadPoolThread, "#12");
447
448                                         called2 = true;
449                                         b.Invoke (null);
450                                         return null;
451                                 },
452                                 l => {
453                                         called = true;
454                                 },
455                                 "h", TaskCreationOptions.AttachedToParent);
456
457                         Assert.AreEqual (TaskCreationOptions.None, task.CreationOptions, "#1");
458                         Assert.AreEqual (TaskCreationOptions.AttachedToParent, (TaskCreationOptions) task.AsyncState, "#2");
459                         Assert.IsTrue (task.Wait (5000), "#3");
460                         Assert.IsTrue (called, "#4");
461                         Assert.IsTrue (called2, "#5");
462                 }
463         }
464 }
465 #endif