// Plinq supresses OCE(externalCT) occuring in worker threads and then throws a single OCE(ct) // if a manual OCE(ct) is thrown but ct is not canceled, Plinq should not suppress it, else things // get confusing... // ONLY an OCE(ct) for ct.IsCancellationRequested=true is co-operative cancellation private static bool Bugfix632544_OnlySuppressOCEifCTCanceled() { bool passed = true; #if !PFX_LEGACY_3_5 TestHarness.TestLog("* PlinqCancellationTests.Bugfix632544_OnlySuppressOCEifCTCanceled()"); AggregateException caughtException = null; CancellationTokenSource cts = new CancellationTokenSource(); CancellationToken externalToken = cts.Token; try { Enumerable.Range(1, 10).AsParallel() .WithCancellation(externalToken) .Select( x => { if (x % 2 == 0) { throw new OperationCanceledException(externalToken); } return(x); } ) .ToArray(); } catch (AggregateException ae) { caughtException = ae; } passed &= TestHarnessAssert.IsNotNull(caughtException, "We expect this OCE(ct) to merely be aggregated."); #endif return(passed); }
// a specific repro where inner queries would see an ODE on the merged cancellation token source // when the implementation involved disposing and recreating the token on each worker thread private static bool Cancellation_ODEIssue() { bool passed = true; AggregateException caughtException = null; try { Enumerable.Range(0, 1999).ToArray() .AsParallel().AsUnordered() .WithExecutionMode(ParallelExecutionMode.ForceParallelism) .Zip <int, int, int>( Enumerable.Range(1000, 20).Select <int, int>(_item => (int)_item).AsParallel().AsUnordered(), (first, second) => { throw new OperationCanceledException(); }) .ForAll(x => { }); } catch (AggregateException ae) { caughtException = ae; } //the failure was an ODE coming out due to an ephemeral disposed merged cancellation token source. passed &= TestHarnessAssert.IsTrue(caughtException != null, "We expect an aggregate exception with OCEs in it."); return(passed); }
/// <summary> /// /// Bug535510: /// This bug occured because the QuerySettings structure was not being deep-cloned during /// query-opening. As a result, the concurrent inner-enumerators (for the RHS operators) /// that occur in SelectMany were sharing CancellationState that they should not have. /// The result was that enumerators could falsely believe they had been canceled when /// another inner-enumerator was disposed. /// /// Note: the failure was intermittent. this test would fail about 1 in 2 times on mikelid1 (4-core). /// </summary> /// <returns></returns> private static bool BugFix535510_CloningQuerySettingsForSelectMany() { bool passed = true; TestHarness.TestLog("* PlinqCancellationTests.BugFix535510_CloningQuerySettingsForSelectMany()"); var plinq_src = ParallelEnumerable.Range(0, 1999).AsParallel(); Exception caughtException = null; try { var inner = ParallelEnumerable.Range(0, 20).AsParallel().Select(_item => _item); var output = plinq_src .SelectMany( _x => inner, (_x, _y) => _x ) .ToArray(); } catch (Exception ex) { caughtException = ex; } passed &= TestHarnessAssert.IsNull(caughtException, "No exception should occur."); return(passed); }
private static bool MultiplesWithCancellationIsIllegal() { bool passed = true; TestHarness.TestLog("* PlinqCancellationTests.MultiplesWithCancellationIsIllegal()"); InvalidOperationException caughtException = null; try { CancellationTokenSource cs = new CancellationTokenSource(); CancellationToken ct = cs.Token; var query = Enumerable.Range(1, 10).AsParallel().WithDegreeOfParallelism(2).WithDegreeOfParallelism(2); query.ToArray(); } catch (InvalidOperationException ex) { caughtException = ex; //Console.WriteLine("IOE caught. message = " + ex.Message); } passed &= TestHarnessAssert.IsNotNull(caughtException, "An exception should be thrown."); return(passed); }
public static bool PreCanceledToken_SimpleEnumerator() { bool passed = true; TestHarness.TestLog("* PlinqCancellationTests.PreCanceledToken_SimpleEnumerator()"); OperationCanceledException caughtException = null; var cs = new CancellationTokenSource(); cs.Cancel(); int[] srcEnumerable = Enumerable.Range(0, 1000).ToArray(); ThrowOnFirstEnumerable <int> throwOnFirstEnumerable = new ThrowOnFirstEnumerable <int>(srcEnumerable); try { var query = throwOnFirstEnumerable .AsParallel() .WithCancellation(cs.Token); foreach (var item in query) { } } catch (OperationCanceledException ex) { caughtException = ex; } passed &= TestHarnessAssert.IsNotNull(caughtException, "an OCE should be throw during query opening"); passed &= TestHarnessAssert.AreEqual(cs.Token, OCEHelper.ExtractCT(caughtException), "The OCE should reference the cancellation token."); return(passed); }
// throwing a fake OCE(ct) when the ct isn't canceled should produce an AggregateException. private static bool Bugfix640886_SetOperationsThrowAggregateOnCancelOrDispose_2() { bool passed = true; TestHarness.TestLog("* PlinqCancellationTests.Bugfix640886_SetOperationsThrowAggregateOnCancelOrDispose_2()"); try { CancellationTokenSource cs = new CancellationTokenSource(); var plinq = Enumerable.Range(0, 50) .AsParallel().WithCancellation(cs.Token) .WithDegreeOfParallelism(1) #if PFX_LEGACY_3_5 .Union(Enumerable.Range(0, 10).AsParallel().Select <int, int>(x => { throw new OperationCanceledException(); })); #else .Union(Enumerable.Range(0, 10).AsParallel().Select <int, int>(x => { throw new OperationCanceledException(cs.Token); })); #endif var walker = plinq.GetEnumerator(); while (walker.MoveNext()) { Thread.Sleep(1); } walker.MoveNext(); passed &= TestHarnessAssert.Fail("AggregateException was expected, but no exception occured."); }
// After running a plinq query, we expect the internal cancellation token source to have been disposed. // The critical thing is that there are no callbacks left hanging on the external tokens callback list, else we // could be causing an accumulation of junk that will not GC until the external token goes away (possibly never). private static bool Bugfix626345_PlinqShouldDisposeLinkedToken() { bool passed = true; TestHarness.TestLog("* PlinqCancellationTests.Bugfix626345_PlinqShouldDisposeLinkedToken()"); #if DEBUG // Only run these in debug mode, because they rely on a debug-only property. PropertyInfo callbackCountProperty = typeof(CancellationTokenSource). GetProperty("CallbackCount", BindingFlags.Instance | BindingFlags.NonPublic); if (callbackCountProperty == null) { TestHarness.TestLog(" - Error: CancellationTokenSource.CallbackCount property not found; was it removed?"); return(false); } Func <CancellationTokenSource, int> getCallbackCount = _ => (int)callbackCountProperty.GetValue(_, null); CancellationTokenSource cts = new CancellationTokenSource(); CancellationToken ct = cts.Token; // ForAll Enumerable.Range(1, 10).AsParallel().WithCancellation(ct).ForAll((x) => { }); passed &= TestHarnessAssert.IsTrue(getCallbackCount(cts) == 0, "The callback list should be empty."); // Built-in-aggregation Enumerable.Range(1, 10).AsParallel().WithCancellation(ct).Average(); passed &= TestHarnessAssert.IsTrue(getCallbackCount(cts) == 0, "The callback list should be empty."); // Manual aggregation Enumerable.Range(1, 10).AsParallel().WithCancellation(ct).Aggregate((a, b) => a + b); passed &= TestHarnessAssert.IsTrue(getCallbackCount(cts) == 0, "The callback list should be empty."); // ToArray (uses ToList, which enumerates the query with foreach()) Enumerable.Range(1, 10).AsParallel().WithCancellation(ct).ToArray(); passed &= TestHarnessAssert.IsTrue(getCallbackCount(cts) == 0, "The callback list should be empty."); // AsynchronousChannelMergeEnumerator foreach (int x in Enumerable.Range(1, 10).AsParallel().WithCancellation(ct).Select(xx => xx)) { } passed &= TestHarnessAssert.IsTrue(getCallbackCount(cts) == 0, "The callback list should be empty."); // SynchronousChannelMergeEnumerator foreach (int x in Enumerable.Range(1, 10).AsParallel().WithCancellation(ct).WithMergeOptions(ParallelMergeOptions.FullyBuffered)) { } passed &= TestHarnessAssert.IsTrue(getCallbackCount(cts) == 0, "The callback list should be empty."); // Fallback to sequential foreach (int x in Enumerable.Range(1, 10).AsParallel().WithCancellation(ct).Where(xx => true).Skip(4)) { } passed &= TestHarnessAssert.IsTrue(getCallbackCount(cts) == 0, "The callback list should be empty."); #endif return(passed); }
// Tests that the shared state variable seems to be working correctly. private static bool RunManualResetEventSlimTest4_CombinedStateTests() { bool passed = true; TestHarness.TestLog("* RunManualResetEventSlimTest4_CombinedStateTests()"); ManualResetEventSlim mres = new ManualResetEventSlim(false, 100); int expectedCount = Environment.ProcessorCount == 1 ? 1 : 100; passed &= TestHarnessAssert.AreEqual(expectedCount, mres.SpinCount, "Spin count did not write/read correctly, expected " + expectedCount + ", actual " + mres.SpinCount); passed &= TestHarnessAssert.IsFalse(mres.IsSet, "Set did not read correctly."); mres.Set(); passed &= TestHarnessAssert.IsTrue(mres.IsSet, "Set did not write/read correctly."); return(passed); }
private static bool CancellationTokenTest_NonSorting_SynchronousMergerEnumeratorDispose() { bool passed = true; TestHarness.TestLog("* PlinqCancellationTests.CancellationTokenTest_NonSorting_SynchronousMergerEnumeratorDispose()"); int size = 10000; CancellationTokenSource tokenSource = new CancellationTokenSource(); Exception caughtException = null; var query = Enumerable.Range(1, size).AsParallel() .WithCancellation(tokenSource.Token) .Select( i => { Thread.Sleep(100); return(i); }).WithMergeOptions(ParallelMergeOptions.FullyBuffered); IEnumerator <int> enumerator = query.GetEnumerator(); ThreadPool.QueueUserWorkItem( (arg) => { Thread.Sleep(1000); enumerator.Dispose(); }); try { // This query should run for at least a few seconds due to the sleeps in the select-delegate for (int j = 0; j < 1000; j++) { enumerator.MoveNext(); } } catch (ObjectDisposedException ex) { caughtException = ex; } passed &= TestHarnessAssert.IsNotNull(caughtException, "An ObjectDisposedException should be thrown"); return(passed); }
// Tests timeout on an event that is never set. private static bool RunManualResetEventSlimTest3_ConstructorTests() { bool passed = true; TestHarness.TestLog("* RunManualResetEventSlimTest3_ConstructorTests()"); passed &= TestHarnessAssert.EnsureExceptionThrown( () => new ManualResetEventSlim(false, 2048), //max value is 2047. typeof(ArgumentOutOfRangeException), "The max value for spin count is 2047. An ArgumentException should be thrown."); passed &= TestHarnessAssert.EnsureExceptionThrown( () => new ManualResetEventSlim(false, -1), typeof(ArgumentOutOfRangeException), "The min value for spin count is 0. An ArgumentException should be thrown."); return(passed); }
private static bool CancellationTokenTest_Sorting_ToArray() { bool passed = true; TestHarness.TestLog("* PlinqCancellationTests.CancellationTokenTest_Sorting_ToArray()"); int size = 10000; CancellationTokenSource tokenSource = new CancellationTokenSource(); ThreadPool.QueueUserWorkItem( (arg) => { Thread.Sleep(500); tokenSource.Cancel(); }); OperationCanceledException caughtException = null; try { // This query should run for at least a few seconds due to the sleeps in the select-delegate var query = Enumerable.Range(1, size).AsParallel() .WithCancellation(tokenSource.Token) .Select( i => { Thread.Sleep(1); return(i); }); query.ToArray(); } catch (OperationCanceledException ex) { caughtException = ex; } passed &= TestHarnessAssert.IsNotNull(caughtException, "An OCE should be thrown"); passed &= TestHarnessAssert.AreEqual(tokenSource.Token, OCEHelper.ExtractCT(caughtException), "The OCE should reference the external token."); return(passed); }
private static bool RunThreadLocalTest5_Dispose() { TestHarness.TestLog("* RunThreadLocalTest5_Dispose()"); ThreadLocal <string> tl = new ThreadLocal <string>(() => "dispose test"); string value = tl.Value; tl.Dispose(); if (!TestHarnessAssert.EnsureExceptionThrown(() => { string tmp = tl.Value; }, typeof(ObjectDisposedException), "The Value property of the disposed ThreadLocal object should throw ODE")) { return(false); } if (!TestHarnessAssert.EnsureExceptionThrown(() => { bool tmp = tl.IsValueCreated; }, typeof(ObjectDisposedException), "The IsValueCreated property of the disposed ThreadLocal object should throw ODE")) { return(false); } if (!TestHarnessAssert.EnsureExceptionThrown(() => { string tmp = tl.ToString(); }, typeof(ObjectDisposedException), "The ToString method of the disposed ThreadLocal object should throw ODE")) { return(false); } // test recycling the combination index; tl = new ThreadLocal <string>(() => null); if (tl.IsValueCreated) { TestHarness.TestLog("* Filed, reusing the same index kept the old value and didn't use the new value."); return(false); } if (tl.Value != null) { TestHarness.TestLog("* Filed, reusing the same index kept the old value and didn't use the new value."); return(false); } return(true); }
private static bool RunManualResetEventSlimTest5_Dispose() { bool passed = true; TestHarness.TestLog("* RunManualResetEventSlimTest5_Dispose()"); ManualResetEventSlim mres = new ManualResetEventSlim(false); mres.Dispose(); passed &= TestHarnessAssert.EnsureExceptionThrown( () => mres.Reset(), typeof(ObjectDisposedException), "The object has been disposed, should throw ObjectDisposedException."); passed &= TestHarnessAssert.EnsureExceptionThrown( () => mres.Wait(0), typeof(ObjectDisposedException), "The object has been disposed, should throw ObjectDisposedException."); passed &= TestHarnessAssert.EnsureExceptionThrown( () => { WaitHandle handle = mres.WaitHandle; }, typeof(ObjectDisposedException), "The object has been disposed, should throw ObjectDisposedException."); mres = new ManualResetEventSlim(false);; ManualResetEvent mre = (ManualResetEvent)mres.WaitHandle; mres.Dispose(); passed &= TestHarnessAssert.EnsureExceptionThrown( () => mre.WaitOne(0, false), typeof(ObjectDisposedException), "The underlying event object has been disposed, should throw ObjectDisposedException."); return(passed); }
private static bool CancellationTokenTest_NonSorting_ToArray_ExternalCancel() { bool passed = true; TestHarness.TestLog("* PlinqCancellationTests.CancellationTokenTest_NonSorting_ToArray_ExternalCancel()"); int size = 10000; CancellationTokenSource tokenSource = new CancellationTokenSource(); OperationCanceledException caughtException = null; ThreadPool.QueueUserWorkItem( (arg) => { Thread.Sleep(1000); tokenSource.Cancel(); }); try { int[] output = Enumerable.Range(1, size).AsParallel() .WithCancellation(tokenSource.Token) .Select( i => { Thread.Sleep(100); return(i); }).ToArray(); } catch (OperationCanceledException ex) { caughtException = ex; } passed &= TestHarnessAssert.IsNotNull(caughtException, "An ObjectDisposedException should be thrown"); passed &= TestHarnessAssert.AreEqual(tokenSource.Token, OCEHelper.ExtractCT(caughtException), "The OCE should reference the external cancellation token."); return(passed); }
private static bool Bug599487_MoveNextAfterQueryOpeningFailsIsIllegal() { TestHarness.TestLog("* MoveNextAfterQueryOpeningFailsIsIllegal()"); bool success = true; var query = Enumerable.Range(0, 10) .AsParallel() .Select <int, int>(x => { throw new ApplicationException(); }) .OrderBy(x => x); IEnumerator <int> enumerator = query.GetEnumerator(); //moveNext will cause queryOpening to fail (no element generated) success &= TestHarnessAssert.EnsureExceptionThrown( () => enumerator.MoveNext(), typeof(AggregateException), "An AggregateException(containing ApplicationException) should be thrown"); //moveNext after queryOpening failed success &= TestHarnessAssert.EnsureExceptionThrown( () => enumerator.MoveNext(), typeof(InvalidOperationException), "A second attempt to enumerate should cause InvalidOperationException"); return(success); }
/// <summary>Tests for the Value factory throws an exception.</summary> /// <returns>True if the tests succeeds, false otherwise.</returns> private static bool RunLazyTest9_Exceptions() { TestHarness.TestLog("* RunLazyTest9_Exceptions()"); int counter = m_exceptionCounter; Lazy <string> l = new Lazy <string>(() => { m_exceptionCounter++; int zero = 0; int x = 1 / zero; return(""); }, true); string s; if (!TestHarnessAssert.EnsureExceptionThrown(() => s = l.Value, typeof(DivideByZeroException), "Expected DivideByZeroException")) { TestHarness.TestLog("failed"); return(false); } if (!TestHarnessAssert.EnsureExceptionThrown(() => s = l.Value, typeof(DivideByZeroException), "Expected DivideByZeroException")) { TestHarness.TestLog("failed"); return(false); } if (!TestHarnessAssert.AreEqual <int>(counter + 1, m_exceptionCounter, "value factory has been called twise and it should be called only once.")) { TestHarness.TestLog("failed"); return(false); } if (l.IsValueCreated) { TestHarness.TestLog("failed* IsValueCreated should return false."); return(false); } return(true); }
// REPRO 1 -- cancellation private static bool Bugfix640886_SetOperationsThrowAggregateOnCancelOrDispose_1() { bool passed = true; TestHarness.TestLog("* PlinqCancellationTests.Bugfix640886_SetOperationsThrowAggregateOnCancelOrDispose_1()"); var mre = new ManualResetEvent(false); var plinq_src = Enumerable.Range(0, 5000000).Select(x => { if (x == 0) { mre.Set(); } return(x); }); Task t = null; try { CancellationTokenSource cs = new CancellationTokenSource(); var plinq = plinq_src .AsParallel().WithCancellation(cs.Token) .WithDegreeOfParallelism(1) .Union(Enumerable.Range(0, 10).AsParallel()); var walker = plinq.GetEnumerator(); t = Task.Factory.StartNew(() => { mre.WaitOne(); cs.Cancel(); }); while (walker.MoveNext()) { Thread.Sleep(1); var item = walker.Current; } walker.MoveNext(); passed &= TestHarnessAssert.Fail("OperationCanceledException was expected, but no exception occured."); } catch (OperationCanceledException) { //This is expected. } catch (Exception e) { passed &= TestHarnessAssert.Fail("OperationCanceledException was expected, but a different exception occured."); TestHarness.TestLog(e.ToString()); } if (t != null) { t.Wait(); } return(passed); }