using System.Threading; using NUnit.Framework; using Amib.Threading; namespace SmartThreadPoolTests { /// /// Summary description for TestCancel. /// [TestFixture] [Category("TestCancel")] public class TestCancel { /// /// 1. Create STP in suspended mode /// 2. Queue work item into the STP /// 3. Cancel the work item /// 4. Work item's GetResult should throw WorkItemCancelException /// [Test] [ExpectedException(typeof(WorkItemCancelException))] public void CancelInQueueWorkItem() { STPStartInfo stpStartInfo = new STPStartInfo(); stpStartInfo.StartSuspended = true; SmartThreadPool stp = new SmartThreadPool(stpStartInfo); IWorkItemResult wir = stp.QueueWorkItem(arg => null); wir.Cancel(); Assert.IsTrue(wir.IsCanceled); try { wir.GetResult(); } finally { stp.Shutdown(); } } /// /// 1. Create STP /// 2. Queue work item that takes some time /// 3. Wait for it to start /// 4. Cancel the work item (soft) /// 5. Work item's GetResult should throw WorkItemCancelException /// [Test] [ExpectedException(typeof(WorkItemCancelException))] public void CancelInProgressWorkItemSoft() { ManualResetEvent waitToStart = new ManualResetEvent(false); SmartThreadPool stp = new SmartThreadPool(); IWorkItemResult wir = stp.QueueWorkItem( state => { waitToStart.Set(); Thread.Sleep(100); return null; } ); waitToStart.WaitOne(); wir.Cancel(false); Assert.IsTrue(wir.IsCanceled); try { wir.GetResult(); } finally { stp.Shutdown(); } } /// /// 1. Create STP /// 2. Queue work item that takes some time /// 3. Wait for it to start /// 4. Cancel the work item (soft) /// 5. Work item's GetResult should throw WorkItemCancelException /// [Test] [ExpectedException(typeof(WorkItemCancelException))] public void CancelCancelledWorkItemAbort() { ManualResetEvent waitToStart = new ManualResetEvent(false); SmartThreadPool stp = new SmartThreadPool(); IWorkItemResult wir = stp.QueueWorkItem( state => { waitToStart.Set(); while (true) { Thread.Sleep(1000); } return null; } ); waitToStart.WaitOne(); wir.Cancel(false); Assert.IsTrue(wir.IsCanceled); bool completed = stp.WaitForIdle(1000); Assert.IsFalse(completed); wir.Cancel(true); try { wir.GetResult(); } finally { stp.Shutdown(); } } /// /// 1. Create STP /// 2. Queue work item that: /// a. Sleep for 0.1 seconds /// b. Increment the counter /// 3. Wait for the work item to start /// 4. Cancel the work item (abort) /// 5. Make sure the work item result indicates the work item has been cancelled. /// 6. Make sure the counter incrementation didn't happen /// 7. Work item's GetResult should throw WorkItemCancelException /// [Test] [ExpectedException(typeof(WorkItemCancelException))] public void CancelInProgressWorkItemAbort() { ManualResetEvent waitToStart = new ManualResetEvent(false); int counter = 0; SmartThreadPool stp = new SmartThreadPool(); IWorkItemResult wir = stp.QueueWorkItem( state => { waitToStart.Set() ; Thread.Sleep(100); ++counter; return null; } ); waitToStart.WaitOne(); wir.Cancel(true); Assert.IsTrue(wir.IsCanceled); Assert.AreEqual(counter, 0); try { wir.GetResult(); } finally { stp.Shutdown(); } } /// /// 1. Create STP /// 2. Queue work item that takes some time /// 3. Wait for it to start /// 4. Cancel the work item (soft) /// 5. Make sure, in the work item, that SmartThreadPool.IsWorkItemCanceled is true /// 5. Wait for the STP to get idle /// 6. Work item's GetResult should throw WorkItemCancelException /// [Test] public void CancelInProgressWorkItemSoftWithSample() { bool cancelled = false; ManualResetEvent waitToStart = new ManualResetEvent(false); ManualResetEvent waitToComplete = new ManualResetEvent(false); SmartThreadPool stp = new SmartThreadPool(); IWorkItemResult wir = stp.QueueWorkItem( state => { waitToStart.Set(); waitToComplete.WaitOne(); cancelled = SmartThreadPool.IsWorkItemCanceled; return null; } ); waitToStart.WaitOne(); wir.Cancel(false); waitToComplete.Set(); stp.WaitForIdle(); Assert.IsTrue(cancelled); stp.Shutdown(); } /// /// 1. Create STP /// 2. Queue work item that takes some time /// 3. Wait for it to start /// 4. Cancel the work item (soft) /// 5. Don't call to SmartThreadPool.IsWorkItemCanceled /// 6. Wait for the STP to get idle /// 7. Work item's GetResult should throw WorkItemCancelException /// [Test] [ExpectedException(typeof(WorkItemCancelException))] public void CancelInProgressWorkItemSoftWithIgnoreSample() { ManualResetEvent waitToStart = new ManualResetEvent(false); ManualResetEvent waitToComplete = new ManualResetEvent(false); SmartThreadPool stp = new SmartThreadPool(); IWorkItemResult wir = stp.QueueWorkItem( state => { waitToStart.Set(); Thread.Sleep(100); waitToComplete.WaitOne(); return null; } ); waitToStart.WaitOne(); wir.Cancel(false); waitToComplete.Set(); stp.WaitForIdle(); // Throws WorkItemCancelException wir.GetResult(); stp.Shutdown(); } /// /// 1. Create STP /// 2. Queue work item that takes some time /// 3. Wait for it to start /// 4. Cancel the work item (soft) /// 5. Call to AbortOnWorkItemCancel /// 5. Wait for the STP to get idle /// 6. Make sure nothing ran in the work item after the AbortOnWorkItemCancel /// [Test] public void CancelInProgressWorkItemSoftWithAbortOnWorkItemCancel() { bool abortFailed = false; ManualResetEvent waitToStart = new ManualResetEvent(false); ManualResetEvent waitToCancel = new ManualResetEvent(false); SmartThreadPool stp = new SmartThreadPool(); IWorkItemResult wir = stp.QueueWorkItem( state => { waitToStart.Set(); waitToCancel.WaitOne(); SmartThreadPool.AbortOnWorkItemCancel(); abortFailed = true; return null; }); waitToStart.WaitOne(); wir.Cancel(false); waitToCancel.Set(); stp.WaitForIdle(); Assert.IsTrue(wir.IsCanceled); Assert.IsFalse(abortFailed); stp.Shutdown(); } /// /// 1. Create STP in suspended mode /// 2. Queue work item into the STP /// 3. Cancel the work item /// 4. Start the STP /// 5. Wait for the STP to get idle /// 6. Work item's GetResult should throw WorkItemCancelException /// 7. Cancel the work item again /// 8. Work item's GetResult should throw WorkItemCancelException /// [Test] [ExpectedException(typeof(WorkItemCancelException))] public void CancelCanceledWorkItem() { STPStartInfo stpStartInfo = new STPStartInfo(); stpStartInfo.StartSuspended = true; SmartThreadPool stp = new SmartThreadPool(stpStartInfo); IWorkItemResult wir = stp.QueueWorkItem(state => null); int counter = 0; wir.Cancel(); try { wir.GetResult(); } catch (WorkItemCancelException ce) { ce.GetHashCode(); ++counter; } Assert.AreEqual(counter, 1); wir.Cancel(); try { wir.GetResult(); } finally { stp.Shutdown(); } } /// /// 1. Create STP /// 2. Queue work item into the STP /// 3. Wait for the STP to get idle /// 4. Work item's GetResult should return value /// 4. Cancel the work item /// 5. Work item's GetResult should return value /// [Test] public void CancelCompletedWorkItem() { SmartThreadPool stp = new SmartThreadPool(); IWorkItemResult wir = stp.QueueWorkItem( state => 1 ); stp.WaitForIdle(); Assert.AreEqual(wir.GetResult(), 1); wir.Cancel(); Assert.AreEqual(wir.GetResult(), 1); stp.Shutdown(); } /// /// 1. Zero counter /// 2. Create STP /// 3. Queue 10 work items, that sleep and then increment the counter, into the STP /// 4. Cancel the STP /// 5. Make sure the counter is still zero /// [Test] public void CancelSTPWorkItems() { // I don't use lock on the counter, since any number above 0 is a failure. // In the worst case counter will be equal to 1 which is still not 0. int counter = 0; SmartThreadPool stp = new SmartThreadPool(); for (int i = 0; i < 10; i++) { stp.QueueWorkItem( state => { Thread.Sleep(500); ++counter; return null; } ); } Thread.Sleep(100); stp.Cancel(true); Assert.AreEqual(counter, 0); stp.Shutdown(); } /// /// 1. Zero counter /// 2. Create STP /// 3. Create a WIG /// 4. Queue 10 work items, that sleep and then increment the counter, into the WIG /// 5. Cancel the WIG /// 6. Wait for the WIG to become idle /// 7. Make sure the counter is still zero /// [Test] public void CancelWIGWorkItems() { // I don't use lock on the counter, since any number above 0 is a failure. // In the worst case counter will be equal to 1 which is still not 0. int counter = 0; SmartThreadPool stp = new SmartThreadPool(); IWorkItemsGroup wig = stp.CreateWorkItemsGroup(10); for (int i = 0; i < 10; i++) { wig.QueueWorkItem( state => { Thread.Sleep(500); ++counter; return null; } ); } Thread.Sleep(100); wig.Cancel(true); Assert.AreEqual(counter, 0); stp.Shutdown(); } /// /// 1. Zero global counter /// 2. Create STP /// 3. Create a WIG1 in suspended mode /// 4. Create a WIG2 in suspended mode /// 5. Queue 5 work items, that increment the global counter, into the WIG1 /// 6. Queue 7 work items, that increment the global counter, into the WIG2 /// 7. Cancel the WIG1 /// 8. Start the WIG1 /// 9. Start the WIG2 /// 10. Wait for the STP to get idle /// 11. Make sure the global counter is 7 /// [Test] public void Cancel1WIGof2WorkItems() { int counter1 = 0; int counter2 = 0; SmartThreadPool stp = new SmartThreadPool(); IWorkItemsGroup wig1 = stp.CreateWorkItemsGroup(3); IWorkItemsGroup wig2 = stp.CreateWorkItemsGroup(3); for (int i = 0; i < 3; i++) { wig1.QueueWorkItem( state => { Interlocked.Increment(ref counter1); Thread.Sleep(500); Interlocked.Increment(ref counter1); return null; } ); } for (int i = 0; i < 3; i++) { wig2.QueueWorkItem( state => { Thread.Sleep(500); Interlocked.Increment(ref counter2); return null; } ); } while (counter1 < 3) { Thread.Sleep(1); } wig1.Cancel(true); stp.WaitForIdle(); Assert.AreEqual(3, counter1, "Cancelled WIG1"); Assert.AreEqual(3, counter2, "Normal WIG2"); stp.Shutdown(); } } }