1 // ExecutionBlocksTest.cs
3 // Copyright (c) 2012 Petr Onderka
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 using System.Collections.Generic;
26 using System.Threading;
27 using System.Threading.Tasks;
28 using System.Threading.Tasks.Dataflow;
29 using NUnit.Framework;
31 namespace MonoTests.System.Threading.Tasks.Dataflow {
33 public class ExecutionBlocksTest {
34 static IEnumerable<ITargetBlock<int>> GetExecutionBlocksWithAction(Action action)
36 yield return new ActionBlock<int> (i => action());
37 yield return new TransformBlock<int, int> (i =>
42 yield return new TransformManyBlock<int, int> (i =>
45 return Enumerable.Empty<int> ();
49 static IEnumerable<ITargetBlock<int>> GetExecutionBlocksWithAsyncAction (
50 Func<int, Task> action, ExecutionDataflowBlockOptions options)
52 yield return new ActionBlock<int> (action, options);
53 yield return new TransformBlock<int, int> (
54 i => action (i).ContinueWith (
60 yield return new TransformManyBlock<int, int> (
61 i => action (i).ContinueWith (
65 return Enumerable.Empty<int> ();
70 public void ExceptionTest ()
72 var exception = new Exception ();
73 var blocks = GetExecutionBlocksWithAction (() => { throw exception; });
74 foreach (var block in blocks) {
75 Assert.IsFalse (block.Completion.Wait (100));
80 AssertEx.Throws<AggregateException> (() => block.Completion.Wait (100));
81 Assert.AreEqual (1, ae.InnerExceptions.Count);
82 Assert.AreSame (exception, ae.InnerException);
87 public void NoProcessingAfterFaultTest ()
90 int ranAfterFault = 0;
91 var evt = new ManualResetEventSlim ();
93 var blocks = GetExecutionBlocksWithAction (() =>
95 if (Thread.VolatileRead (ref shouldRun) == 0) {
103 foreach (var block in blocks) {
108 Assert.IsTrue (block.Post (1));
109 Assert.IsTrue (block.Post (2));
111 Assert.IsFalse (block.Completion.Wait (100));
112 Assert.AreEqual (0, ranAfterFault);
114 block.Fault (new Exception ());
116 Assert.IsFalse (block.Completion.Wait (100));
121 AssertEx.Throws<AggregateException> (() => block.Completion.Wait (100));
125 Assert.AreEqual (0, Thread.VolatileRead (ref ranAfterFault));
130 public void AsyncTest ()
132 var tcs = new TaskCompletionSource<int> ();
135 var scheduler = new TestScheduler ();
137 var blocks = GetExecutionBlocksWithAsyncAction (
139 tcs.Task.ContinueWith (t => Thread.VolatileWrite (ref result, i + t.Result)),
140 new ExecutionDataflowBlockOptions { TaskScheduler = scheduler });
142 foreach (var block in blocks) {
143 Assert.IsTrue (block.Post (1));
145 scheduler.ExecuteAll ();
147 Thread.MemoryBarrier ();
149 Assert.AreEqual (0, result);
155 // the continuation should be executed on the configured TaskScheduler
156 Assert.AreEqual (0, result);
158 scheduler.ExecuteAll ();
160 Assert.AreEqual (11, result);
162 tcs = new TaskCompletionSource<int> ();
163 Thread.VolatileWrite (ref result, 0);
168 public void AsyncExceptionTest ()
170 var scheduler = new TestScheduler ();
171 var exception = new Exception ();
173 var blocks = GetExecutionBlocksWithAsyncAction (
176 var tcs = new TaskCompletionSource<int> ();
177 tcs.SetException (exception);
180 new ExecutionDataflowBlockOptions { TaskScheduler = scheduler });
182 foreach (var block in blocks) {
183 Assert.IsTrue (block.Post (1));
185 // the task should be executed on the configured TaskScheduler
186 Assert.IsFalse (block.Completion.Wait (100));
188 scheduler.ExecuteAll ();
191 AssertEx.Throws<AggregateException> (() => block.Completion.Wait (100)).
194 Assert.AreEqual (1, ae.InnerExceptions.Count);
195 Assert.AreSame (exception, ae.InnerException);