예제 #1
0
        public void TransitionErrorDoesntBreakWorkflow()
        {
            var gate = new ManualResetEventSlim(false);

            var stateMachineBuilder = StateMachineFactory.CreateBuilder <TestEnum, TestTransitionEnum, int>();
            var startState          = stateMachineBuilder.AddState(TestEnum.Start);
            var endState            = stateMachineBuilder.AddState(TestEnum.End);

            startState.AddValidTransition(TestTransitionEnum.Stopping, endState)
            .AddTransitionFunction(ctx =>
            {
                throw new Exception();
            });

            endState.OnStateEnter(ctx =>
            {
                gate.Set();
                return(Task.CompletedTask);
            });

            var stateMachine = stateMachineBuilder.Compile();
            var context      = stateMachine.StartStateMachine(TestEnum.Start, 5, executeStageEntry: true);

            context.Post(TestTransitionEnum.Stopping);

            Assert.IsTrue(gate.Wait(StateMachineTests.gateTimeout));
        }
예제 #2
0
        public void TestSimpleStateMachineTransition()
        {
            var waitEvent = new ManualResetEventSlim(false);

            var stateMachineBuilder = StateMachineFactory.CreateBuilder <TestEnum, TestTransitionEnum, int>();
            var startState          = stateMachineBuilder.AddState(TestEnum.Start);
            var endState            = stateMachineBuilder.AddState(TestEnum.End)
                                      .OnStateEnter(ctx =>
            {
                waitEvent.Set();
                return(Task.CompletedTask);
            });

            startState.AddValidTransition(TestTransitionEnum.Stopping, endState);

            var stateMachine = stateMachineBuilder.Compile();
            var context      = stateMachine.StartStateMachine(TestEnum.Start, 5);

            context.Post(TestTransitionEnum.Stopping);

            if (false == waitEvent.Wait(StateMachineTests.gateTimeout))
            {
                Assert.Fail();
            }

            waitEvent.Dispose();
        }
예제 #3
0
        public void TestDoubleTransition()
        {
            var gate = new ManualResetEventSlim(false);
            var stateMachineBuilder = StateMachineFactory.CreateBuilder <TestEnum, TestTransitionEnum, int>();
            var startState          = stateMachineBuilder.AddState(TestEnum.Start);
            var middleState         = stateMachineBuilder.AddState(TestEnum.Middle);
            var endState            = stateMachineBuilder.AddState(TestEnum.End);

            startState.AddValidTransition(TestTransitionEnum.Middling, middleState);
            middleState.AddValidTransition(TestTransitionEnum.Stopping, endState);

            middleState.OnStateEnter(ctx =>
            {
                ctx.Post(TestTransitionEnum.Stopping);
                return(Task.CompletedTask);
            });

            endState.OnStateEnter(ctx =>
            {
                gate.Set();
                return(Task.CompletedTask);
            });

            var stateMachine = stateMachineBuilder.Compile();

            var context = stateMachine.StartStateMachine(TestEnum.Start, 4);

            context.Post(TestTransitionEnum.Middling);

            if (false == gate.Wait(10000))
            {
                Assert.Fail();
            }
        }
예제 #4
0
        public async Task TestRethrownLocalExceptionDoesntHitGlobalHandler()
        {
            var hitGlobalHander = false;
            var hitLocalHandler = false;

            var builder = StateMachineFactory.CreateBuilder <TestEnum, TestTransitionEnum, int>();
            var one     = builder.AddState(TestEnum.Start)
                          .OnStateEnter(xtc => throw new Exception())
                          .SetOnEnterFaultHandler((ctx, ex) =>
            {
                hitLocalHandler = true;
                throw ex;
            });
            var two = builder.AddState(TestEnum.End);

            builder.SetGlobalFaultHandler((ctx, ex) => { hitGlobalHander = true; });

            one.AddValidTransition(TestTransitionEnum.Stopping, two);

            var stateMachine = builder.Compile();
            var context      = stateMachine.StartStateMachine(TestEnum.Start, 5, true);

            await Task.Delay(1000);

            Assert.AreEqual(StateMachineLifetime.Error, context.CurrentLifecycle);
            Assert.IsTrue(hitLocalHandler);
            Assert.IsFalse(hitGlobalHander);
        }
예제 #5
0
        public void TestAddStateDuplicate()
        {
            var builder  = StateMachineFactory.CreateBuilder <TestEnum, TestTransitionEnum, object>();
            var newState = builder.AddState(TestEnum.Start);

            Assert.ThrowsException <ArgumentException>(() => builder.AddState(TestEnum.Start));
        }
예제 #6
0
        public void TestStateMachineCompileEmpty()
        {
            var builder = StateMachineFactory.CreateBuilder <TestEnum, TestTransitionEnum, object>();

            var stateMachine = builder.Compile();

            Assert.IsFalse(stateMachine.States.Any());
        }
예제 #7
0
        public void TestAddState()
        {
            var builder  = StateMachineFactory.CreateBuilder <TestEnum, TestTransitionEnum, object>();
            var newState = builder.AddState(TestEnum.Start);

            Assert.IsNotNull(newState);
            Assert.AreEqual(TestEnum.Start, ((StateBuilder <TestEnum, TestTransitionEnum, object>)newState).State);
        }
예제 #8
0
        public void TestStateMachineOneState()
        {
            var builder = StateMachineFactory.CreateBuilder <TestEnum, TestTransitionEnum, object>();

            builder.AddState(TestEnum.Start);

            var stateMachine = builder.Compile();

            Assert.AreEqual(TestEnum.Start, stateMachine.States.First().State);
        }
예제 #9
0
        public void TestContextExists()
        {
            var stateMachineBuilder = StateMachineFactory.CreateBuilder <TestEnum, TestTransitionEnum, int>();
            var startState          = stateMachineBuilder.AddState(TestEnum.Start);

            var stateMachine = stateMachineBuilder.Compile();
            var context      = stateMachine.StartStateMachine(TestEnum.Start, 5);

            Assert.AreSame(context, stateMachine.Contexts.Single());
        }
예제 #10
0
        public void TestAddNextStateDuplicate()
        {
            var builder    = StateMachineFactory.CreateBuilder <TestEnum, TestTransitionEnum, object>();
            var startState = builder.AddState(TestEnum.Start);

            var endState = builder.AddState(TestEnum.End);

            startState.AddValidTransition(TestTransitionEnum.Stopping, endState);

            Assert.ThrowsException <ArgumentException>(() => startState.AddValidTransition(TestTransitionEnum.Stopping, endState));
        }
예제 #11
0
        public void TestInvalidTransition()
        {
            var stateMachineBuilder = StateMachineFactory.CreateBuilder <TestEnum, TestTransitionEnum, int>();
            var startState          = stateMachineBuilder.AddState(TestEnum.Start);
            var endState            = stateMachineBuilder.AddState(TestEnum.End);

            var stateMachine = stateMachineBuilder.Compile();
            var context      = stateMachine.StartStateMachine(TestEnum.Start, 5);

            Assert.ThrowsException <InvalidOperationException>(() => context.Post(TestTransitionEnum.Middling));
        }
예제 #12
0
        public void TestStateMachineTransition()
        {
            var builder = StateMachineFactory.CreateBuilder <TestEnum, TestTransitionEnum, object>();
            var start   = builder.AddState(TestEnum.Start);
            var end     = builder.AddState(TestEnum.End);

            start.AddValidTransition(TestTransitionEnum.Stopping, end);

            var stateMachine = builder.Compile();

            Assert.AreEqual(2, stateMachine.States.Count);
        }
        public void TestBackAndForth()
        {
            var oneToTwo = false;
            var twoToOne = false;
            var two      = false;

            var factory = StateMachineFactory.CreateBuilder <NumberedTestEnum, TransitionEnum, int>();

            var finishGate = new ManualResetEventSlim(false);

            var first = factory.AddState(NumberedTestEnum.One);

            first.OnStateEnter(ctx =>
            {
                finishGate.Set();
                return(Task.CompletedTask);
            });
            var second = factory.AddState(NumberedTestEnum.Two);

            second.OnStateEnter(ctx =>
            {
                two = true;
                ctx.Post(TransitionEnum.T2);
                return(Task.CompletedTask);
            });

            first.AddValidTransition(TransitionEnum.T1, second)
            .AddTransitionFunction(ctx =>
            {
                oneToTwo = true;
                return(Task.CompletedTask);
            });
            second.AddValidTransition(TransitionEnum.T2, first)
            .AddTransitionFunction(ctx =>
            {
                twoToOne = true;
                return(Task.CompletedTask);
            });

            var stateMachine = factory.Compile();
            var session      = stateMachine.StartStateMachine(NumberedTestEnum.One, 5);

            session.Post(TransitionEnum.T1);

            var one = finishGate.Wait(StateMachineCirclularTests.GateWait);

            Thread.MemoryBarrier();
            Assert.IsTrue(oneToTwo);
            Assert.IsTrue(two);
            Assert.IsTrue(twoToOne);
            Assert.IsTrue(one);
        }
예제 #14
0
        public void TestAddNextState()
        {
            var builder    = StateMachineFactory.CreateBuilder <TestEnum, TestTransitionEnum, object>();
            var startState = builder.AddState(TestEnum.Start);
            var nextState  = builder.AddState(TestEnum.End);

            Assert.IsFalse(((StateBuilder <TestEnum, TestTransitionEnum, object>)startState).Transitions.Any());
            Assert.IsFalse(((StateBuilder <TestEnum, TestTransitionEnum, object>)nextState).Transitions.Any());
            startState.AddValidTransition(TestTransitionEnum.Stopping, nextState);

            Assert.AreSame(nextState, ((StateBuilder <TestEnum, TestTransitionEnum, object>)startState).Transitions.Single().EndState);
            Assert.IsFalse(((StateBuilder <TestEnum, TestTransitionEnum, object>)nextState).Transitions.Any());
        }
        public void TestFullLoop()
        {
            var factory = StateMachineFactory.CreateBuilder <NumberedTestEnum, TransitionEnum, int>();

            var finishGate = new ManualResetEventSlim(false);
            var states     = Enum.GetValues(typeof(NumberedTestEnum)).Cast <NumberedTestEnum>().Select(s => factory.AddState(s)).ToArray();

            var statecounts = new int[states.Length];

            for (var i = 0; i < states.Length; i++)
            {
                states[i].AddValidTransition(TransitionEnum.T1, states[(i + 1) % states.Length]);

                if (i != 0)
                {
                    var locali = i;
                    states[i].OnStateEnter(ctx =>
                    {
                        statecounts[locali]++;
                        ctx.Post(TransitionEnum.T1);
                        return(Task.CompletedTask);
                    });
                }
            }

            states[0].OnStateEnter(ctx =>
            {
                if (++statecounts[0] < 5)
                {
                    ctx.Post(TransitionEnum.T1);
                }
                else
                {
                    finishGate.Set();
                }

                return(Task.CompletedTask);
            });

            var stateMachine = factory.Compile();
            var context      = stateMachine.StartStateMachine(NumberedTestEnum.One, 5);

            context.Post(TransitionEnum.T1);

            Assert.IsTrue(finishGate.Wait(StateMachineCirclularTests.GateWait));
            Assert.AreEqual(5, statecounts[0]);

            context.Dispose();
        }
예제 #16
0
        public async Task TestSimpleFaultStopsMachine()
        {
            var builder = StateMachineFactory.CreateBuilder <TestEnum, TestTransitionEnum, int>();
            var one     = builder.AddState(TestEnum.Start)
                          .OnStateEnter(xtc => throw new Exception());
            var two = builder.AddState(TestEnum.End);

            one.AddValidTransition(TestTransitionEnum.Stopping, two);

            var stateMachine = builder.Compile();
            var context      = stateMachine.StartStateMachine(TestEnum.Start, 5, true);

            await Task.Delay(1000);

            Assert.AreEqual(StateMachineLifetime.Error, context.CurrentLifecycle);
        }
예제 #17
0
        public void Start()
        {
            var idleState      = new IdleState();
            var enterDoorState = new EnterDoorState(_doors, _mover);
            var followingState = new FollowingState(_targetChaser);
            var attackState    = new AttackState(_timeProvider, _attackInterval, _attacker);

            var brainStateMachineBuilder = _stateMachineFactory.CreateBuilder <ZombieBrainContextFactory, ZombieBrainContext, ZombieContextUpdater, IEntity>();

            brainStateMachineBuilder.ConfigureState(idleState, b =>
            {
                b.If(c => !c.IsInsideScene)
                .ThenSetState(enterDoorState);
            });

            brainStateMachineBuilder.ConfigureState(enterDoorState, b =>
            {
                b.If(c => c.Target == null)
                .ThenSetState(idleState);
                b.If(c => c.IsInsideScene && c.Target != null)
                .ThenSetState(followingState);
            });

            brainStateMachineBuilder.ConfigureState(followingState, b =>
            {
                b.If(c => c.Target == null)
                .ThenSetState(idleState);
                b.If(c => c.Target != null && c.TargetReached)
                .ThenSetState(attackState);
            });

            brainStateMachineBuilder.ConfigureState(attackState, b =>
            {
                b.If(c => c.Target == null)
                .ThenSetState(idleState);
                b.If(c => c.Target != null && !c.TargetReached)
                .ThenSetState(followingState);
            });

            var contextFactory = new ZombieBrainContextFactory();
            var contextUpdater = new ZombieContextUpdater(_targetChaser, _targetLocator, _positionDetector);

            _stateMachine = brainStateMachineBuilder.BuildRoot(contextFactory, contextUpdater);
            _stateMachine.Start(idleState);
        }
예제 #18
0
        public void BlockDoublePendingTransition()
        {
            var gate = new ManualResetEventSlim(false);

            var stateMachineBuilder = StateMachineFactory.CreateBuilder <TestEnum, TestTransitionEnum, int>();
            var startState          = stateMachineBuilder.AddState(TestEnum.Start);
            var endState            = stateMachineBuilder.AddState(TestEnum.End);

            startState.AddValidTransition(TestTransitionEnum.Stopping, endState);
            startState.OnStateEnter(ctx =>
            {
                Assert.IsTrue(gate.Wait(StateMachineTests.gateTimeout));
                return(Task.CompletedTask);
            });

            var stateMachine = stateMachineBuilder.Compile();
            var context      = stateMachine.StartStateMachine(TestEnum.Start, 5, executeStageEntry: true);

            context.Post(TestTransitionEnum.Stopping);
            Assert.ThrowsException <ArgumentException>(() => context.Post(TestTransitionEnum.Stopping));

            gate.Set();
        }
예제 #19
0
        public void TestPendingTransition()
        {
            var factory = StateMachineFactory.CreateBuilder <NumberedTestEnum, TransitionEnum, int>();

            var leftState2 = false;

            var finishGate = new ManualResetEventSlim(false);

            var first  = factory.AddState(NumberedTestEnum.One);
            var second = factory.AddState(NumberedTestEnum.Two);

            second.OnStateEnter(async ctx =>
            {
                ctx.Post(TransitionEnum.T2);
                await Task.Delay(1000);
                leftState2 = true;
            });
            var third = factory.AddState(NumberedTestEnum.Three);

            third.OnStateEnter(ctx =>
            {
                Assert.IsTrue(leftState2);
                finishGate.Set();
                return(Task.CompletedTask);
            });

            first.AddValidTransition(TransitionEnum.T1, second);
            second.AddValidTransition(TransitionEnum.T2, third);

            var stateMachine = factory.Compile();
            var session      = stateMachine.StartStateMachine(NumberedTestEnum.One, 5);

            session.Post(TransitionEnum.T1);

            Assert.IsTrue(finishGate.Wait(StateMachineConcurrencyTests.GateWait));
        }
예제 #20
0
        public void TestStateMachineTransitionWhileInProgress()
        {
            var waitEvent = new ManualResetEventSlim(false);

            var stateMachineBuilder = StateMachineFactory.CreateBuilder <TestEnum, TestTransitionEnum, int>();
            var startState          = stateMachineBuilder.AddState(TestEnum.Start);
            var endState            = stateMachineBuilder.AddState(TestEnum.End);

            startState.AddValidTransition(TestTransitionEnum.Stopping, endState)
            .AddTransitionFunction(ctx =>
            {
                waitEvent.Wait(StateMachineTests.gateTimeout);
                return(Task.CompletedTask);
            });

            var stateMachine = stateMachineBuilder.Compile();
            var context      = stateMachine.StartStateMachine(TestEnum.Start, 5);

            context.Post(TestTransitionEnum.Stopping);
            Assert.ThrowsException <Exception>(() => context.Post(TestTransitionEnum.Stopping));

            waitEvent.Set();
            waitEvent.Dispose();
        }