Mercurial > pub > ImplabNet
diff Implab.Test/PollingComponentTests.cs @ 203:4d9830a9bbb8 v2
Added 'Fail' method to RunnableComponent which allows component to move from
Running to Failed state.
Added PollingComponent a timer based runnable component
More tests
Added FailPromise a thin class to wrap exceptions
Fixed error handling in SuccessPromise classes.
author | cin |
---|---|
date | Tue, 18 Oct 2016 17:49:54 +0300 |
parents | |
children | 8200ab154c8a |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Implab.Test/PollingComponentTests.cs Tue Oct 18 17:49:54 2016 +0300 @@ -0,0 +1,230 @@ +using System; +using System.Reflection; +using System.Threading; +using Implab.Parallels; +using Implab.Components; +using Implab.Test.Mock; + +#if MONO + +using NUnit.Framework; +using TestClassAttribute = NUnit.Framework.TestFixtureAttribute; +using TestMethodAttribute = NUnit.Framework.TestAttribute; +using AssertFailedException = NUnit.Framework.AssertionException; +#else + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +#endif + +namespace Implab.Test { + [TestClass] + public class PollingComponentTests { + static void ShouldThrow(Action action) { + try { + action(); + Assert.Fail(); + } catch (AssertFailedException) { + throw; + } catch { + } + } + + [TestMethod] + public void NormalFlowTest() { + var comp = new MockPollingComponent(TimeSpan.FromMilliseconds(1), null, false); + + Assert.AreEqual(ExecutionState.Created, comp.State); + + comp.Init(); + + Assert.AreEqual(ExecutionState.Ready, comp.State); + + comp.Start().Join(1000); + + Assert.AreEqual(ExecutionState.Running, comp.State); + + comp.Stop().Join(1000); + + Assert.AreEqual(ExecutionState.Disposed, comp.State); + + } + + [TestMethod] + public void ShouldStartTicks() { + var signal = new Signal(); + + var comp = new MockPollingComponent(TimeSpan.FromMilliseconds(1), null, true); + comp.MockTick = ct => { + signal.Set(); + return Promise.SUCCESS; + }; + + comp.Start().Join(1000); + signal.Wait(1000); + comp.Stop().Join(1000); + } + + [TestMethod] + public void StopShouldWaitForTickToComplete() { + var comp = new MockPollingComponent(TimeSpan.FromMilliseconds(1), null, true); + var signal = new Signal(); + var promise = new Promise(); + + // timer should tick once + comp.MockTick = ct => { + signal.Set(); + return promise; + }; + + // start timer + comp.Start().Join(1000); + + signal.Wait(); // wait for tick + + // try to stop component + var stopping = comp.Stop(); + + Assert.AreEqual(ExecutionState.Stopping, comp.State); + ShouldThrow(() => stopping.Join(100)); + Assert.AreEqual(ExecutionState.Stopping, comp.State); + + // complete operation + promise.Resolve(); + + // the component should stop normally + stopping.Join(1000); + + Assert.AreEqual(ExecutionState.Disposed, comp.State); + } + + [TestMethod] + public void ShouldRecoverAfterTickError() { + var ticks = 0; + + var comp = new MockPollingComponent(TimeSpan.FromMilliseconds(1), null, true); + var signal = new Signal(); // will signal when timer fires 10 times + + comp.MockTick = ct => { + ticks++; + if (ticks == 10) + signal.Set(); + // each time handler dies + throw new Exception("tainted handler"); + }; + + comp.Start(); + + signal.Wait(1000); + + comp.Stop().Join(1000); + + Assert.AreEqual(ExecutionState.Disposed, comp.State); + } + + [TestMethod] + public void StopCancelHandlerOnStop() { + var comp = new MockPollingComponent(TimeSpan.FromMilliseconds(1), null, true); + var started = new Signal(); + bool cancelled = false; + + // timer should tick once + comp.MockTick = ct => { + started.Set(); + + while(!ct.IsCancellationRequested) { + Thread.Sleep(1); + } + + cancelled = true; + + throw new OperationCanceledException(); + }; + + // start timer + comp.Start().Join(1000); + + started.Wait(); // wait for tick + + // try to stop component + comp.Stop().Join(1000); + + Assert.AreEqual(true, cancelled); + + Assert.AreEqual(ExecutionState.Disposed, comp.State); + } + + [TestMethod] + public void FailTickOnStopShouldBeIgnored() { + var comp = new MockPollingComponent(TimeSpan.FromMilliseconds(1), null, true); + var started = new Signal(); + var finish = new Signal(); + + // timer should tick once + comp.MockTick = ct => { + started.Set(); + finish.Wait(); + // component is in stopping state here + throw new Exception("Die, die, die!!!"); + }; + + + comp.MockOnError = comp.CallComponentFail; + + // start timer + comp.Start().Join(1000); + + started.Wait(); // wait for tick + + // try to stop component + var stopping = comp.Stop(); + + // the component is in stopping state but it is waiting for the tick handler to complete + finish.Set(); // signal the tick handler to finish + + // tick handler should stop rather soon + stopping.Join(1000); + + // validate the component is disposed + Assert.AreEqual(ExecutionState.Disposed, comp.State); + } + + [TestMethod] + public void FailTickShouldFailComponent() { + var comp = new MockPollingComponent(TimeSpan.FromMilliseconds(1), null, true); + var started = new Signal(); + var finish = new Signal(); + + // timer should tick once + comp.MockTick = ct => { + started.Set(); + throw new Exception("Die, die, die!!!"); + }; + + + comp.MockOnError = err => { + comp.CallComponentFail(err); + finish.Set(); + }; + + // start timer + comp.Start().Join(1000); + + started.Wait(); // wait for tick + + finish.Wait(); + + // try to stop component + ShouldThrow(() => comp.Stop()); + + Assert.AreEqual(ExecutionState.Failed, comp.State); + Assert.IsNotNull(comp.LastError); + Assert.AreEqual("Die, die, die!!!", comp.LastError.Message); + + comp.Dispose(); + Assert.AreEqual(ExecutionState.Disposed, comp.State); + } + + } +} +