##// END OF EJS Templates
Added 'Fail' method to RunnableComponent which allows component to move from...
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.

File last commit:

r203:4d9830a9bbb8 v2
r203:4d9830a9bbb8 v2
Show More
PollingComponentTests.cs
230 lines | 6.3 KiB | text/x-csharp | CSharpLexer
/ Implab.Test / PollingComponentTests.cs
cin
Added 'Fail' method to RunnableComponent which allows component to move from...
r203 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);
}
}
}