Exemple #1
0
        public static WorkplanDummy CreatePausableSub()
        {
            var workplan = new WorkplanDummy();

            var inital   = Workflow.CreateConnector("Start", NodeClassification.Start);
            var complete = Workflow.CreateConnector("End", NodeClassification.End);

            workplan.Add(inital, complete);

            var step = new DummyStep(1, "A");

            step.Inputs[0] = inital;
            workplan.Add(step);

            var aComplete = Workflow.CreateConnector("A1");

            workplan.Add(aComplete);
            step.Outputs[0] = aComplete;

            var finalStep = new PausableStep();

            finalStep.Inputs[0] = aComplete;
            workplan.Add(finalStep);
            finalStep.Outputs[0] = complete;

            return(workplan);
        }
        public void PredictorShouldSupportLoops()
        {
            // Arrange
            var workplan  = WorkplanDummy.WithLoop();
            var predictor = Workflow.PathPrediction(workplan);
            var executor  = new SingleLoopExecution();
            NodeClassification prediction = NodeClassification.Intermediate;

            predictor.PathPrediction += (sender, args) => prediction = args.PredictedOutcome;

            var engine = Workflow.CreateEngine(workplan, new NullContext());

            engine.ExecutedWorkflow.Transitions.OfType <DummyTransition>().ForEach(dt => dt.ResultOutput = -1); // Disable automatic execution

            // Act
            var finalResult = NodeClassification.Intermediate;

            engine.Completed           += (sender, place) => { finalResult = place.Classification; };
            engine.TransitionTriggered += (sender, transition) => ThreadPool.QueueUserWorkItem(executor.ResumeAsync, transition);
            predictor.Monitor(engine);
            engine.Start();

            // Assert
            while (finalResult == NodeClassification.Intermediate)
            {
                Thread.Sleep(1); // Await completion
            }
            Assert.AreEqual(finalResult, prediction, "Predication was incorrect");
        }
        public void SubWorkflow()
        {
            // Arrange
            var workplan = WorkplanDummy.CreateSub();
            var step     = new SubworkflowStep(workplan);
            var exits    = workplan.Connectors.Where(c => c.Classification.HasFlag(NodeClassification.Exit)).ToArray();

            // Act
            var trans = step.CreateInstance(null);

            // Assert
            Assert.IsInstanceOf <SubworkflowTransition>(trans);
            Assert.AreEqual(2, step.Outputs.Length);
            Assert.AreEqual(2, step.OutputDescriptions.Length);
            var success = step.OutputDescriptions[0];

            Assert.AreEqual("End", success.Name);
            Assert.AreEqual(OutputType.Success, success.OutputType);
            Assert.AreEqual(exits[0].Id, success.MappingValue);
            var failed = step.OutputDescriptions[1];

            Assert.AreEqual("Failed", failed.Name);
            Assert.AreEqual(OutputType.Failure, failed.OutputType);
            Assert.AreEqual(exits[1].Id, failed.MappingValue);
        }
Exemple #4
0
        public void ExecuteWorkflow(ExecutionPath route, int expectedTransitions, string expectedPath)
        {
            // Arrange
            var workplan = WorkplanDummy.CreateFull();
            var engine   = Workflow.CreateEngine(workplan, new NullContext());

            // Act
            var triggerCount = 0;
            var path         = string.Empty;

            engine.TransitionTriggered += delegate(object sender, ITransition transition)
            {
                var dummy = (DummyTransition)transition;
                if (route == ExecutionPath.Alternative)
                {
                    dummy.ResultOutput = dummy.Outputs.Length - 1;
                }
                triggerCount++;
                path += "->" + dummy.Name;
            };
            engine.Completed += EngineCompleted;
            engine.Start();
            // Synchronus execution means we are done here
            Workflow.Destroy(engine);

            // Assert
            Assert.IsTrue(_completed);
            Assert.AreEqual(expectedTransitions, triggerCount, "Less transitions triggered than expected!");
            Assert.AreEqual(expectedPath, path, "Workflow engine did not take the correct path!");
        }
        public void SubWorkflowTransition()
        {
            // Arrange
            var workplan = WorkplanDummy.CreateSub();
            var exits    = workplan.Connectors.Where(c => c.Classification.HasFlag(NodeClassification.Exit)).ToArray();
            var outputs  = new[]
            {
                new OutputDescription {
                    MappingValue = (int)exits[0].Id
                },
                new OutputDescription {
                    MappingValue = (int)exits[1].Id
                },
            };
            var trans = new SubworkflowTransition(Workflow.CreateEngine(workplan, new NullContext()), TransitionBase.CreateIndexResolver(outputs))
            {
                Id      = 1,
                Inputs  = new[] { _inputs[0] },
                Outputs = _outputs
            };
            var triggered = new List <ITransition>();

            // Act
            trans.Initialize();
            trans.Triggered += (sender, args) => triggered.Add((ITransition)sender);
            _inputs[0].Add(_token);

            // Assert
            Assert.AreEqual(0, _inputs[0].Tokens.Count());
            Assert.AreEqual(_token, _outputs[0].Tokens.First());
            Assert.AreEqual(2, triggered.Count);
            Assert.IsTrue(triggered.All(t => t is DummyTransition));
        }
Exemple #6
0
        public static WorkplanDummy CreateMixed()
        {
            var workplan = new WorkplanDummy();

            var inital   = Workflow.CreateConnector("Start", NodeClassification.Start);
            var complete = Workflow.CreateConnector("End", NodeClassification.End);

            workplan.Add(inital, complete);

            var step = new DummyStep(1, "A");

            step.Inputs[0] = inital;
            // workplan.Add(step);  // Add first step at the end

            var aComplete = Workflow.CreateConnector("A1");

            workplan.Add(aComplete);
            step.Outputs[0] = aComplete;

            var finalStep = new DummyStep(1, "B");

            finalStep.Inputs[0] = aComplete;
            workplan.Add(finalStep);
            finalStep.Outputs[0] = complete;

            workplan.Add(step); // Mix order of steps

            return(workplan);
        }
Exemple #7
0
        public void PauseAndResume()
        {
            // Arrange
            var workplan = WorkplanDummy.CreatePausable();
            var engine   = Workflow.CreateEngine(workplan, new NullContext());

            engine.TransitionTriggered += (sender, transition) => { };
            engine.Completed           += EngineCompleted;

            // Act
            engine.Start(); // <-- This runs till the first pausable transition
            var snapShot = engine.Pause();

            // Once we resume it will continue
            engine.Start();

            // Assert
            var stepId = workplan.Steps.Single(s => s is PausableStep).Id;

            Assert.IsTrue(_completed);
            Assert.AreEqual(1, snapShot.Holders.Length);
            Assert.AreEqual(stepId, snapShot.Holders[0].HolderId);
            Assert.IsInstanceOf <MainToken>(snapShot.Holders[0].HolderState);
            Assert.AreEqual(1, snapShot.Holders[0].Tokens.Length);
        }
Exemple #8
0
        public void RestoreAndResume()
        {
            // Arrange
            var workplan = WorkplanDummy.CreatePausable();
            var engine   = Workflow.CreateEngine(workplan, new NullContext());
            var stepId   = workplan.Steps.Single(s => s is PausableStep).Id;
            var snapShot = new WorkflowSnapshot
            {
                Holders = new[]
                {
                    new HolderSnapshot
                    {
                        HolderId = stepId,
                        Tokens   = new IToken[] { new MainToken() }
                    }
                }
            };

            // Act
            engine.Restore(snapShot);
            engine.Completed           += EngineCompleted;
            engine.TransitionTriggered += (sender, transition) => { };
            engine.Start(); // <-- This run to the end

            // Assert
            Assert.IsTrue(_completed);
        }
Exemple #9
0
        public static WorkplanDummy WithLoop()
        {
            var workplan = new WorkplanDummy();

            var inital   = Workflow.CreateConnector("Start", NodeClassification.Start);
            var complete = Workflow.CreateConnector("End", NodeClassification.End);
            var failed   = Workflow.CreateConnector("Failed", NodeClassification.Failed);

            workplan.Add(inital, complete, failed);

            var step = new DummyStep(2, "Feed case");

            step.Inputs[0] = inital;
            workplan.Add(step);

            var left = Workflow.CreateConnector("Left");

            workplan.Add(left);
            step.Outputs[0] = left;
            var right = Workflow.CreateConnector("Right");

            workplan.Add(right);
            step.Outputs[1] = right;

            step           = new DummyStep(3, "Mount");
            step.Inputs[0] = left;
            workplan.Add(step);
            step.Outputs[2] = right;
            left            = Workflow.CreateConnector("Merge");
            workplan.Add(left);
            step.Outputs[0] = step.Outputs[1] = left;

            step           = new DummyStep(3, "Set pole");
            step.Inputs[0] = left;
            workplan.Add(step);
            var oldLeft = left;

            left = Workflow.CreateConnector("Pole set");
            workplan.Add(left);
            step.Outputs[0] = left;
            step.Outputs[1] = oldLeft;
            step.Outputs[2] = failed;

            step           = new DummyStep(3, "Set screw");
            step.Inputs[0] = left;
            workplan.Add(step);
            step.Outputs[0] = right;
            step.Outputs[1] = complete;
            step.Outputs[2] = failed;

            var rightOnly = new DummyStep(1, "Remove case");

            rightOnly.Inputs[0]  = right;
            rightOnly.Outputs[0] = failed;
            workplan.Add(rightOnly);

            return(workplan);
        }
Exemple #10
0
        public void ValidateFullSuccess()
        {
            // Arrange
            var workplan = WorkplanDummy.CreateFull();

            // Act
            var validation = Workflow.Validate(workplan, ValidationAspect.DeadEnd | ValidationAspect.LoneWolf);

            // Assert
            Assert.IsTrue(validation.Success, "Validation did not return success for a valid workplan!");
            Assert.AreEqual(0, validation.Errors.Length, "Valid workplan must not report errors!");
        }
Exemple #11
0
        public void ValidateDeadEnd()
        {
            // Arrange
            var workplan = WorkplanDummy.CreateDeadEnd();

            // Act
            var validation = Workflow.Validate(workplan, ValidationAspect.DeadEnd);

            // Assert
            Assert.IsFalse(validation.Success, "Validation did not detect error!");
            Assert.AreEqual(1, validation.Errors.Length, "Validation should have found one error!");
            Assert.IsInstanceOf <DeadEndValidationError>(validation.Errors[0], "Error should be of type \"DeadEndValidationError\"");
            var expected = workplan.Connectors.First(c => c.Name == "DeadEnd");

            Assert.AreEqual(expected.Id, validation.Errors[0].PositionId);
            var error = validation.Errors[0].Print(workplan);

            Assert.NotNull(error);
        }
        public void NoPredictionIfNotPossible()
        {
            // Arrange
            var  workplan  = WorkplanDummy.CreateBig();
            bool triggered = false;
            var  predictor = Workflow.PathPrediction(workplan);

            predictor.PathPrediction += (sender, args) => triggered = triggered = true;

            // Act
            var engine = Workflow.CreateEngine(workplan, new NullContext());

            engine.Completed           += (sender, place) => { };
            engine.TransitionTriggered += (sender, transition) => { };
            predictor.Monitor(engine);
            engine.Start();

            // Assert
            Assert.IsFalse(triggered, "Path predictor should not have been activiated");
        }
Exemple #13
0
        public static WorkplanDummy CreateWithSub()
        {
            var workplan = new WorkplanDummy();

            var inital   = Workflow.CreateConnector("Start", NodeClassification.Start);
            var complete = Workflow.CreateConnector("End", NodeClassification.End);

            workplan.Add(inital, complete);

            var subPlan = CreateSub();

            subPlan.Id = 42;
            var sub = new SubworkflowStep(subPlan);

            sub.Inputs[0]  = inital;
            sub.Outputs[0] = sub.Outputs[0] = complete;
            workplan.Add(sub);

            return(workplan);
        }
        public void SubworkflowPause()
        {
            // Arrange
            var workplan = WorkplanDummy.CreatePausableSub();
            var exits    = workplan.Connectors.Where(c => c.Classification.HasFlag(NodeClassification.Exit)).ToArray();
            var outputs  = new[]
            {
                new OutputDescription {
                    MappingValue = (int)exits[0].Id
                },
            };
            var trans = new SubworkflowTransition(Workflow.CreateEngine(workplan, new NullContext()), TransitionBase.CreateIndexResolver(outputs))
            {
                Id      = 1,
                Inputs  = new[] { _inputs[0] },
                Outputs = _outputs
            };
            var triggered = new List <ITransition>();

            // Act
            trans.Initialize();
            trans.Triggered += (sender, args) => triggered.Add((ITransition)sender);
            _inputs[0].Add(_token);
            trans.Pause();
            var state = trans.InternalState;

            trans.Resume();

            // Assert
            Assert.AreEqual(0, _inputs[0].Tokens.Count());
            Assert.AreEqual(_token, _outputs[0].Tokens.First());
            Assert.AreEqual(1, triggered.Count);
            Assert.IsInstanceOf <WorkflowSnapshot>(state);
            var snapshot = (WorkflowSnapshot)state;

            Assert.AreEqual(1, snapshot.Holders.Length);
            var stepId = workplan.Steps.First(s => s is PausableStep).Id;

            Assert.AreEqual(stepId, snapshot.Holders[0].HolderId);
        }
        public void PredictFailureBeforeCompletion()
        {
            // Arrange
            var stopWatch = new Stopwatch();
            var workplan  = WorkplanDummy.CreateBig();
            var predictor = Workflow.PathPrediction(workplan);

            long predictionTime           = long.MaxValue;
            NodeClassification prediction = NodeClassification.Intermediate;

            predictor.PathPrediction += (sender, args) =>
            {
                prediction     = args.PredictedOutcome;
                predictionTime = stopWatch.ElapsedMilliseconds;
            };

            var engine = Workflow.CreateEngine(workplan, new NullContext());

            engine.ExecutedWorkflow.Transitions.OfType <DummyTransition>().ForEach(dt => dt.ResultOutput = -1); // Disable automatic execution

            // Act
            long completionTime = 0;
            var  finalResult    = NodeClassification.Intermediate;

            engine.Completed           += (sender, place) => { completionTime = stopWatch.ElapsedMilliseconds; finalResult = place.Classification; };
            engine.TransitionTriggered += (sender, transition) => ThreadPool.QueueUserWorkItem(ResumeAsync, transition);
            predictor.Monitor(engine);
            stopWatch.Start();
            engine.Start();

            // Assert
            while (finalResult == NodeClassification.Intermediate)
            {
                Thread.Sleep(1); // Await completion
            }
            stopWatch.Stop();
            Assert.Less(predictionTime, completionTime, "Engine was completed before a prediction was published.");
            Assert.AreEqual(finalResult, prediction, "Predication was incorrect");
        }
Exemple #16
0
        public static WorkplanDummy CreatePausable()
        {
            var workplan = new WorkplanDummy();

            var inital   = Workflow.CreateConnector("Start", NodeClassification.Start);
            var complete = Workflow.CreateConnector("End", NodeClassification.End);

            workplan.Add(inital);
            workplan.Add(complete);

            var step = new DummyStep(1, "A");

            step.Inputs[0] = inital;
            workplan.Add(step);

            var a1 = Workflow.CreateConnector("Before pause");

            workplan.Add(a1);
            step.Outputs[0] = a1;

            var rightOnly = new PausableStep();

            rightOnly.Inputs[0] = a1;
            workplan.Add(rightOnly);
            step.Outputs[0] = a1;

            var b1 = Workflow.CreateConnector("Right complete");

            workplan.Add(b1);
            rightOnly.Outputs[0] = b1;

            var merge = new DummyStep(1, "C");

            merge.Inputs[0] = b1;
            workplan.Add(merge);
            merge.Outputs[0] = complete;

            return(workplan);
        }
Exemple #17
0
        public void InstantiateWorkflow()
        {
            // Arrange
            var workplan = WorkplanDummy.CreateFull();

            // Act
            var context  = new FakeContext();
            var workflow = WorkflowFactory.Instantiate(workplan, context);

            // Simple assert
            Assert.AreEqual(workplan.Connectors.Count(), workflow.Places.Count(), "Not all connectors transformed to places!");
            Assert.AreEqual(workplan.Steps.Count(), workflow.Transitions.Count(), "Not all steps transformed to transitions!");
            Assert.IsTrue(workflow.Transitions.Cast <DummyTransition>().All(t => t.Context == context), "Context not passed to all transitions!");
            // Structure assert
            var transitions = workflow.Transitions;

            Assert.AreEqual(2, transitions[0].Outputs.Length);
            Assert.AreEqual(transitions[0].Outputs[1], transitions[1].Inputs[0]);
            Assert.AreEqual(transitions[0].Outputs[0], transitions[2].Inputs[0]);
            Assert.AreEqual(transitions[1].Outputs[0], transitions[2].Inputs[0]);
            Assert.AreEqual(transitions[2].Outputs[0], transitions[2].Outputs[1]);
            Assert.AreEqual(transitions[2].Outputs[0], workflow.EndPlaces().First());
        }
        public void PublishPredictionAfterInterruption()
        {
            // Arrange
            var workplan  = WorkplanDummy.CreateBig();
            var predictor = Workflow.PathPrediction(workplan);
            NodeClassification prediction = NodeClassification.Intermediate;

            predictor.PathPrediction += (sender, args) => prediction = args.PredictedOutcome;
            // Start and pause engine in
            var engine      = Workflow.CreateEngine(workplan, new NullContext());
            var transitions = engine.ExecutedWorkflow.Transitions.OfType <DummyTransition>();

            transitions.ForEach(dt => dt.ResultOutput = -1); // Disable automatic execution
            transitions.First().ResultOutput = 1;            // Except for the first one
            engine.TransitionTriggered += (sender, transition) => { };
            engine.Start();

            // Act
            var snapshot = engine.Pause(); // Snapshot of the engine in a sure failure path

            engine.Dispose();
            engine = Workflow.CreateEngine(workplan, new NullContext());
            engine.Restore(snapshot); // Restore new engine from the snapshot
            var finalResult = NodeClassification.Intermediate;

            engine.Completed           += (sender, place) => finalResult = place.Classification;
            engine.TransitionTriggered += (sender, transition) => ThreadPool.QueueUserWorkItem(ResumeAsync, transition);
            predictor.Monitor(engine);
            engine.Start(); // This should resume the engine in a failure path and directly raise the event

            // Assert
            while (finalResult == NodeClassification.Intermediate)
            {
                Thread.Sleep(1); // Await completion
            }
            Assert.AreEqual(finalResult, prediction, "Predication was incorrect");
        }
Exemple #19
0
        public static WorkplanDummy CreateLoneWolf()
        {
            var workplan = new WorkplanDummy();

            var inital   = Workflow.CreateConnector("Start", NodeClassification.Start);
            var complete = Workflow.CreateConnector("End", NodeClassification.End);

            workplan.Add(inital, complete);

            var step = new DummyStep(2, "A");

            step.Inputs[0] = inital;
            workplan.Add(step);

            var left = Workflow.CreateConnector("Left");

            workplan.Add(left);
            step.Outputs[0] = left;
            var right = Workflow.CreateConnector("Right");

            workplan.Add(right);
            // step.Outputs[1] = right;  <-- This causes a Lone Wolf validation error

            var rightOnly = new DummyStep(1, "LoneWolf");

            rightOnly.Inputs[0] = right;
            workplan.Add(rightOnly);
            rightOnly.Outputs[0] = left;

            var merge = new DummyStep(2);

            merge.Inputs[0] = left;
            workplan.Add(merge);
            merge.Outputs[0] = merge.Outputs[1] = complete;

            return(workplan);
        }
Exemple #20
0
        public static WorkplanDummy CreateDeadEnd()
        {
            var workplan = new WorkplanDummy();

            var inital   = Workflow.CreateConnector("Start", NodeClassification.Start);
            var complete = Workflow.CreateConnector("End", NodeClassification.End);

            workplan.Add(inital, complete);

            var step = new DummyStep(2, "A");

            step.Inputs[0] = inital;
            workplan.Add(step);

            var left = Workflow.CreateConnector("Left");

            workplan.Add(left);
            step.Outputs[0] = left;
            var right = Workflow.CreateConnector("DeadEnd");

            workplan.Add(right);
            step.Outputs[1] = right;

            var rightOnly = new DummyStep(1);

            workplan.Add(rightOnly);
            rightOnly.Outputs[0] = left;

            var merge = new DummyStep(2);

            merge.Inputs[0] = left;
            workplan.Add(merge);
            merge.Outputs[0] = merge.Outputs[1] = complete;

            return(workplan);
        }