view Implab.Test/RunnableComponentTests.cs @ 205:8200ab154c8a v2

Added ResetState to RunnableComponent to reset in case of failure Added StateChanged event to IRunnable Renamed Promise.SUCCESS -> Promise.Success Added Promise.FromException Renamed Bundle -> PromiseAll in PromiseExtensions
author cin
date Tue, 25 Oct 2016 17:40:33 +0300
parents 4d9830a9bbb8
children 7d07503621fe
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, error) => {
                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, error) => {
                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;
            Exception lastError = null;
            comp.MockDispose = (disposing, error) => {
                disposed = true;
                lastError = error;
            };

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

    }
}