view Implab.Test/RunnableComponentTests.cs @ 209:a867536c68fc v2

Bound promise to CancellationToken Added new states to ExecutionSate enum. Added Safe.Guard() method to handle cleanup of the result of the promise
author cin
date Wed, 16 Nov 2016 03:06:08 +0300
parents 7d07503621fe
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 RunnableComponentTests {

        static void ShouldThrow(Action action) {
            try {
                action();
                Assert.Fail();
            } catch (AssertFailedException) {
                throw;
            } catch {
            }
        }



        [TestMethod]
        public void NormalFlowTest() {
            var comp = new MockRunnableComponent(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 InitFailTest() {
            var comp = new MockRunnableComponent(false) {
                MockInit = () => {
                    throw new Exception("BAD");
                }
            };

            ShouldThrow(() => comp.Start());
            ShouldThrow(() => comp.Stop());
            Assert.AreEqual(ExecutionState.Created, comp.State);

            ShouldThrow(comp.Initialize);

            Assert.AreEqual(ExecutionState.Failed, comp.State);

            ShouldThrow(() => comp.Start());
            ShouldThrow(() => comp.Stop());
            Assert.AreEqual(ExecutionState.Failed, comp.State);

            comp.Dispose();
            Assert.AreEqual(ExecutionState.Disposed, comp.State);
        }

        [TestMethod]
        public void DisposedTest() {

            var comp = new MockRunnableComponent(false);
            comp.Dispose();

            ShouldThrow(() => comp.Start());
            ShouldThrow(() => comp.Stop());
            ShouldThrow(comp.Initialize);

            Assert.AreEqual(ExecutionState.Disposed, comp.State);
        }

        [TestMethod]
        public void ShouldCallDisposeOnStop() {
            var comp = new MockRunnableComponent(true);

            bool disposed = false;
            comp.MockDispose = (disposing) => {
                disposed = true;
            };

            comp.Start().Join(1000);
            comp.Stop().Join(1000);

            ShouldThrow(() => comp.Start());
            ShouldThrow(() => comp.Stop());
            ShouldThrow(comp.Initialize);

            Assert.AreEqual(ExecutionState.Disposed, comp.State);
            Assert.IsTrue(disposed);
        }

        [TestMethod]
        public void ShouldNotCallDisposeOnStop() {
            var comp = new MockRunnableComponent(true, true);

            bool disposed = false;
            comp.MockDispose = (disposing) => {
                disposed = true;
            };

            comp.Start().Join(1000);
            comp.Stop().Join(1000);

            Assert.AreEqual(ExecutionState.Ready, comp.State);
            Assert.IsFalse(disposed);
        }

        [TestMethod]
        public void SelfDisposeOnStop() {
            var comp = new MockRunnableComponent(true, true);

            bool disposed = false;
            comp.MockDispose = (disposing) => {
                disposed = true;
            };

            comp.Start().Join(1000);
            comp.Stop().Join(1000);

            Assert.AreEqual(ExecutionState.Ready, comp.State);
            Assert.IsFalse(disposed);

            comp.MockStop = () => {
                comp.Dispose();
                return Promise.Success;
            };

            comp.Start().Join(1000);
            comp.Stop().Join(1000);

            Assert.AreEqual(ExecutionState.Disposed, comp.State);
            Assert.IsTrue(disposed);
        }

        [TestMethod]
        public void StartCancelTest() {
            var comp = new MockRunnableComponent(true) {
                MockStart = () => PromiseHelper.Sleep(100000, 0)
            };

            var p = comp.Start();
            Assert.AreEqual(ExecutionState.Starting, comp.State);
            p.Cancel();
            ShouldThrow(() => p.Join(1000));
            Assert.AreEqual(ExecutionState.Failed, comp.State);

            Assert.IsTrue(comp.LastError is OperationCanceledException);

            comp.Dispose();
        }

        [TestMethod]
        public void StartStopTest() {
            var stop = new Signal();
            var comp = new MockRunnableComponent(true) {
                MockStart = () => PromiseHelper.Sleep(100000, 0),
                MockStop = () => AsyncPool.RunThread(stop.Wait)
            };

            var p1 = comp.Start();
            var p2 = comp.Stop();
            // should enter stopping state

            ShouldThrow(p1.Join);
            Assert.IsTrue(p1.IsCancelled);
            Assert.AreEqual(ExecutionState.Stopping, comp.State);

            stop.Set();
            p2.Join(1000);
            Assert.AreEqual(ExecutionState.Disposed, comp.State);
        }

        [TestMethod]
        public void StartStopFailTest() {
            var comp = new MockRunnableComponent(true) {
                MockStart = () => PromiseHelper.Sleep(100000, 0).Then(null,null,x => { throw new Exception("I'm dead"); })
            };

            comp.Start();
            var p = comp.Stop();
            // if Start fails to cancel, should fail to stop
            ShouldThrow(() => p.Join(1000));
            Assert.AreEqual(ExecutionState.Failed, comp.State);
            Assert.IsNotNull(comp.LastError);
            Assert.AreEqual("I'm dead", comp.LastError.Message);
        }

        [TestMethod]
        public void StopCancelTest() {
            var comp = new MockRunnableComponent(true) {
                MockStop = () => PromiseHelper.Sleep(100000, 0)
            };

            comp.Start();
            var p = comp.Stop();
            Assert.AreEqual(ExecutionState.Stopping, comp.State);
            p.Cancel();
            ShouldThrow(() => p.Join(1000));
            Assert.AreEqual(ExecutionState.Failed, comp.State);
            Assert.IsTrue(comp.LastError is OperationCanceledException);

            comp.Dispose();
        }

    }
}