[Test] public void ForEachStopsAsSoonAsExceptionThrownAt( [Values(Parallelism / 2, Parallelism, Parallelism * 2)] int cancelAt) { T[] sources = TestData <T> .MakeTestArray(_sampleSize); List <T> completed = new List <T>(_sampleSize); _sut = new ParallelCompletion <T, int>(_executor, _localInit, (t, s, l) => { Thread.Sleep(s.CurrentIndex == 0 ? Delays.ShortMillis : 10); if (s.CurrentIndex == cancelAt) { throw new Exception(); } if (!s.ShouldExitCurrentIteration) { lock (completed) completed.Add(t); } else { Assert.That(s.LowestBreakIteration, Is.Null); Assert.That(s.IsExceptional, Is.True); Assert.That(s.IsStopped, Is.False); } return(0); }, _localFinally); Assert.Catch(() => _sut.ForEach(sources, Parallelism)); Assert.That(completed, Has.No.Member(sources[0])); ThreadManager.JoinAndVerify(); }
[Test] public void ForEachStopsAsSoonAsStopCalledAt( [Values(Parallelism / 2, Parallelism, Parallelism * 2)] int cancelAt) { T[] sources = TestData <T> .MakeTestArray(_sampleSize); List <T> completed = new List <T>(_sampleSize); _sut = new ParallelCompletion <T>(_executor, (t, s) => { Thread.Sleep(s.CurrentIndex == 0 ? Delays.ShortMillis : 10); if (s.CurrentIndex == cancelAt) { s.Stop(); } else { if (!s.ShouldExitCurrentIteration) { lock (completed) completed.Add(t); } else { Assert.That(s.LowestBreakIteration, Is.Null); Assert.That(s.IsExceptional, Is.False); Assert.That(s.IsStopped, Is.True); } } }); var result = _sut.ForEach(sources, Parallelism); Assert.That(result.IsCompleted, Is.False); Assert.That(completed, Has.No.Member(sources[0])); ThreadManager.JoinAndVerify(); }
[Test] public void ForEachCallsLocalInitBodyLocalFinallyInOrder() { T[] sources = TestData <T> .MakeTestArray(_sampleSize); _sut = new ParallelCompletion <T, int>(_executor, _localInit, _body, _localFinally); _sut.ForEach(sources, Parallelism); ( _localFinally.ActivityOf(x => x(Arg <int> .Is.Anything)).First > _body.ActivityOf(x => x(Arg <T> .Is.Anything, Arg <ILoopState> .Is.Anything, Arg <int> .Is.Anything)).First > _localInit.ActivityOf(x => x()).First ) .AssertOccured(); ( _localFinally.ActivityOf(x => x(Arg <int> .Is.Anything)).Last > _body.ActivityOf(x => x(Arg <T> .Is.Anything, Arg <ILoopState> .Is.Anything, Arg <int> .Is.Anything)).Last > _localInit.ActivityOf(x => x()).Last ) .AssertOccured(); ThreadManager.JoinAndVerify(); }
[Test] public void ForEachLimitsParallismToThreadPoolExecutorCoreSize( [Values(Parallelism - 2, Parallelism + 2)] int coreSize) { var tf = new ManagedThreadFactory(ThreadManager); var executor = new ThreadPoolExecutor(coreSize, Parallelism + 2, TimeSpan.MaxValue, new LinkedBlockingQueue <IRunnable>(1), tf); try { T[] sources = TestData <T> .MakeTestArray(_sampleSize); List <T> results = new List <T>(_sampleSize); var parallel = new ParallelCompletion <T, int>(executor, _localInit, (t, s, l) => { Thread.Sleep(10); lock (results) results.Add(t); return(0); }, _localFinally); parallel.ForEach(sources, Parallelism); Assert.That(results, Is.EquivalentTo(sources)); Assert.That(parallel.ActualDegreeOfParallelism, Is.EqualTo(Math.Min(Parallelism, coreSize))); } finally { executor.ShutdownNow(); } ThreadManager.JoinAndVerify(); }
[Test] public void ForEachChokesOnAnyExceptionFromBody() { var exception = new Exception("exception message"); T[] sources = TestData <T> .MakeTestArray(_sampleSize); _sut = new ParallelCompletion <T, int>(_executor, _localInit, (t, s, l) => { if (Equals(t, sources[0])) { Thread.Sleep(Delays.Short); throw exception; } return(0); }, _localFinally); ThreadManager.StartAndAssertRegistered("Driver", () => { var e = Assert.Throws <AggregateException>(() => _sut.ForEach(sources, Parallelism)); Assert.That(e.InnerException, Is.SameAs(exception)); Assert.That(_executor.ThreadCount.Value, Is.GreaterThanOrEqualTo(2)); }); Thread.Sleep(Delays.Short); ThreadManager.JoinAndVerify(); }
[Test] public void ForEachChokesOnNullParallelOptions() { _sut = new ParallelCompletion <T>(_executor, (t, s) => { }); var e = Assert.Throws <ArgumentNullException>( () => _sut.ForEach(new T[0], null)); Assert.That(e.ParamName, Is.EqualTo("parallelOptions")); }
[Test] public void ForEachReturnsImmediatelyOnEmptySource() { List <T> results = new List <T>(); _sut = new ParallelCompletion <T>(_executor, (t, s) => { lock (results) results.Add(t); }); _sut.ForEach(new T[0], new ParallelOptions()); Assert.That(results, Is.Empty); Assert.That(_executor.ThreadCount.Value, Is.EqualTo(0)); }
[Test] public void ForEachChokesOnNullParallelOptions() { _sut = new ParallelCompletion <T, int>(_executor, _localInit, _body, _localFinally); var e = Assert.Throws <ArgumentNullException>( () => _sut.ForEach(new T[0], null)); Assert.That(e.ParamName, Is.EqualTo("parallelOptions")); }
[Test] public void ForEachUseCurrentThreadWhenParallelistIsOne() { List <T> results = new List <T>(_sampleSize); _sut = new ParallelCompletion <T>(_executor, (t, s) => { Thread.Sleep(10); lock (results) results.Add(t); }); T[] sources = TestData <T> .MakeTestArray(_sampleSize); _sut.ForEach(sources, 1); Assert.That(results, Is.EquivalentTo(sources)); Assert.That(_executor.ThreadCount.Value, Is.EqualTo(0)); }
[Test] public void ForEachRecordsTheLowestOfMultipleBreaks( [Values(Parallelism / 2, Parallelism, Parallelism * 2)] int breakAt) { T[] sources = TestData <T> .MakeTestArray(_sampleSize); _sut = new ParallelCompletion <T>(_executor, (t, s) => BreakAt(s, breakAt)); var result = _sut.ForEach(sources, Parallelism); Assert.That(result.IsCompleted, Is.False); Assert.That(result.LowestBreakIteration, Is.EqualTo(breakAt)); ThreadManager.JoinAndVerify(); }
[Test] public void ForEachDoesNotSumitMoreThenMaxDegreeOfParallelism() { _executor.Delay = Delays.Short; T[] sources = TestData <T> .MakeTestArray(_sampleSize); List <T> results = new List <T>(_sampleSize); _sut = new ParallelCompletion <T>(_executor, (t, s) => { Thread.Sleep(10); lock (results) results.Add(t); }); _sut.ForEach(sources, Parallelism); Assert.That(_executor.ThreadCount.Value, Is.EqualTo(Parallelism)); Assert.That(results, Is.EquivalentTo(sources)); ThreadManager.JoinAndVerify(); }
[Test] public void ForEachCompletesAllSlowTasks([Values(int.MaxValue, 3, 1, 0)] int maxThread) { _executor.Threshold = maxThread; T[] sources = TestData <T> .MakeTestArray(_sampleSize); List <T> results = new List <T>(_sampleSize); _sut = new ParallelCompletion <T>(_executor, (t, s) => { Thread.Sleep(10); lock (results) results.Add(t); }); _sut.ForEach(sources, Parallelism); Assert.That(results, Is.EquivalentTo(sources)); Assert.That(_executor.ThreadCount.Value, Is.EqualTo(Math.Min(Parallelism, maxThread))); ThreadManager.JoinAndVerify(); }
[Test] public void ForEachCompletesAllFaskTasks() { _sampleSize = 200; T[] sources = TestData <T> .MakeTestArray(_sampleSize); List <T> results = new List <T>(_sampleSize); _sut = new ParallelCompletion <T>(_executor, (t, s) => { lock (results) results.Add(t); }); _sut.ForEach(sources, new ParallelOptions { MaxDegreeOfParallelism = Parallelism }); Assert.That(results, Is.EquivalentTo(sources)); Assert.That(_executor.ThreadCount.Value, Is.LessThanOrEqualTo(Parallelism)); ThreadManager.JoinAndVerify(); }
[Test] public void UseLocalToCollect() { List <T> collected = new List <T>(); T[] sources = TestData <T> .MakeTestArray(100); var sut = new ParallelCompletion <T, IList <T> >(_executor, () => new List <T>(), (t, s, l) => { l.Add(t); return(l); }, l => { lock (collected) collected.AddRange(l); }); sut.ForEach(sources, Parallelism); Assert.That(collected, Is.EquivalentTo(sources)); ThreadManager.JoinAndVerify(); }
[Test] public void UseLocalToCount() { object @lock = new object(); int count = 0; T[] sources = TestData <T> .MakeTestArray(_sampleSize); _sut = new ParallelCompletion <T, int>(_executor, () => 0, (t, s, l) => l + 1, l => { lock (@lock) count += l; }); _sut.ForEach(sources, Parallelism); Assert.That(count, Is.EqualTo(_sampleSize)); ThreadManager.JoinAndVerify(); }
[Test] public void ForEachCallsLocalFinallyOnExceptionFromBody() { T[] sources = TestData <T> .MakeTestArray(_sampleSize); Thread failedThread = null; var failedThreadFinalized = false; var sut = new ParallelCompletion <T, Thread>( _executor, () => Thread.CurrentThread, (t, s, l) => { if (TestData <T> .Three.Equals(t)) { failedThread = l; throw new Exception(); } return(l); }, l => { if (l == failedThread) { failedThreadFinalized = true; } }); ThreadManager.StartAndAssertRegistered( "Driver", () => { try { sut.ForEach(sources, Parallelism); Assert.Fail("Expecting System.AggregateException, but didn't occur."); } catch (AggregateException) { } } ); Thread.Sleep(Delays.Short); ThreadManager.JoinAndVerify(); Assert.That(failedThreadFinalized); }
[Test] public void ForEachCompletesIterationsLessThenBreakIndexOf( [Values(Parallelism / 2, Parallelism, Parallelism * 2)] int cancelAt) { T[] sources = TestData <T> .MakeTestArray(_sampleSize); List <T> completed = new List <T>(_sampleSize); _sut = new ParallelCompletion <T, int>(_executor, _localInit, (t, s, l) => { Thread.Sleep(s.CurrentIndex == 0 ? Delays.ShortMillis : 10); if (s.CurrentIndex == cancelAt) { s.Break(); } else { if (!s.ShouldExitCurrentIteration) { lock (completed) completed.Add(t); } else { Assert.That(s.LowestBreakIteration, Is.EqualTo(cancelAt)); Assert.That(s.IsExceptional, Is.False); Assert.That(s.IsStopped, Is.False); } } return(0); }, _localFinally); var result = _sut.ForEach(sources, Parallelism); _localFinally.AssertWasCalled(x => x(0)); Assert.That(result.IsCompleted, Is.False); Assert.That(result.LowestBreakIteration, Is.EqualTo(cancelAt)); Assert.That(completed.Count, Is.GreaterThanOrEqualTo(cancelAt)); Assert.That(completed, Has.Member(sources[0])); ThreadManager.JoinAndVerify(); }
[Test] public void ForEachInnerExceptionIsFromFinallyNotBody() { T[] sources = TestData <T> .MakeTestArray(_sampleSize); Thread failedThread = null; var sut = new ParallelCompletion <T, Thread>( _executor, () => Thread.CurrentThread, (t, s, l) => { if (TestData <T> .Three.Equals(t)) { failedThread = l; throw new Exception("body"); } return(l); }, l => { if (l == failedThread) { throw new Exception("localFinally"); } }); ThreadManager.StartAndAssertRegistered("Driver", () => { try { sut.ForEach(sources, Parallelism); Assert.Fail("Expecting System.AggregateException, but didn't occur."); } catch (AggregateException e) { Assert.That(e.InnerExceptions.Count, Is.GreaterThanOrEqualTo(1)); Assert.That(e.InnerException.Message, Is.EqualTo("localFinally")); } }); ThreadManager.JoinAndVerify(); }