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)); }
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(); }
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(); } }
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); }
public void TestAddStateDuplicate() { var builder = StateMachineFactory.CreateBuilder <TestEnum, TestTransitionEnum, object>(); var newState = builder.AddState(TestEnum.Start); Assert.ThrowsException <ArgumentException>(() => builder.AddState(TestEnum.Start)); }
public void TestStateMachineCompileEmpty() { var builder = StateMachineFactory.CreateBuilder <TestEnum, TestTransitionEnum, object>(); var stateMachine = builder.Compile(); Assert.IsFalse(stateMachine.States.Any()); }
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); }
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); }
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()); }
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)); }
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)); }
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); }
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(); }
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); }
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); }
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(); }
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)); }
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(); }