view Implab.Test/PollingComponentTests.cs @ 220:42814145d472 v2

.csproj changes
author cin
date Tue, 20 Jun 2017 19:45:52 +0300
parents 8200ab154c8a
children
line wrap: on
line source

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.Initialize();

            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);
        }

    }
}