public void StateMachineWillIdleWithT1OrT2()
        {
            // Arrange
            WorkflowTestTrace.Arrange();
            var activity = new StateMachineExample();
            var host = WorkflowApplicationTest.Create(activity);
            var stateTracker = StateTracker.Attach(host.TestWorkflowApplication);

            try
            {
                // Act
                WorkflowTestTrace.Act();
                host.TestWorkflowApplication.RunUntilBookmark(StateTrigger.T1);

                // Assert
                WorkflowTestTrace.Assert();
                Assert.IsTrue(stateTracker.PossibleTransitions.Any(s => s == "T1"));
            }
            finally
            {
                WorkflowTestTrace.Finally();
                host.Tracking.Trace();
            }
        }
        /// <summary>
        /// The create instance and persist.
        /// </summary>
        /// <param name="testdb">
        /// The test database.
        /// </param>
        /// <returns>
        /// The <see cref="WorkflowApplicationTest"/>.
        /// </returns>
        private static WorkflowApplicationTest<StateMachineExample> CreateInstanceAndPersist(
            SqlWorkflowInstanceStoreTest testdb)
        {
            WorkflowTestTrace.Arrange();
            var activity = new StateMachineExample();
            var host = WorkflowApplicationTest.Create(activity);

            var instanceStore = SqlWorkflowInstanceStoreManager.CreateInstanceStore(
                testdb.DatabaseName, testdb.ConnectionString, true);
            host.InstanceStore = instanceStore;
            host.PersistableIdle += args => PersistableIdleAction.Unload;
            var stateTracker = StateTracker.Attach(host.TestWorkflowApplication, instanceStore);

            // Act
            host.TestWorkflowApplication.RunUntilBookmark(StateTrigger.T1);

            Assert.IsTrue(host.WaitForUnloadedEvent());
            return host;
        }
        public void TrackerShouldReportPreviousState()
        {
            var activity = new StateMachineExample();
            var host = WorkflowApplicationTest.Create(activity);
            var tracker = new StateMachineStateTracker(activity);
            Debug.Assert(host != null, "host != null");
            Debug.Assert(host.Extensions != null, "host.Extensions != null");
            host.Extensions.Add(tracker);

            try
            {
                // Using Microsoft.Activities.Extensions run the workflow until a bookmark named "T1"
                Assert.IsInstanceOfType(
                    host.TestWorkflowApplication.RunEpisode("T1", Constants.Timeout), typeof(WorkflowIdleEpisodeResult));

                WorkflowTrace.Information("First Idle");
                tracker.Trace();

                Debug.Assert(tracker.TrackedStateMachines != null, "tracker.TrackedStateMachines != null");
                Assert.AreEqual(1, tracker.TrackedStateMachines.Count);
                var stateTrackerInfo = tracker.TrackedStateMachines.Values.ElementAt(0);
                Debug.Assert(stateTrackerInfo != null, "stateTrackerInfo != null");
                Assert.AreEqual(null, stateTrackerInfo.PreviousState);
                Assert.AreEqual(null, tracker.PreviousState);
                Assert.AreEqual(tracker.PreviousState, stateTrackerInfo.PreviousState);
                Debug.Assert(stateTrackerInfo.Transitions != null, "stateTrackerInfo.Transitions != null");
                Assert.AreEqual(2, stateTrackerInfo.Transitions.Count);
                Assert.AreEqual("T1, T2", stateTrackerInfo.PossibleTransitions);

                // Run until bookmark "T3"
                Assert.IsInstanceOfType(
                    host.TestWorkflowApplication.ResumeEpisodeBookmark("T1", null, "T3"),
                    typeof(WorkflowIdleEpisodeResult));

                WorkflowTrace.Information("Second Idle");
                tracker.Trace();

                // Use the tracker operations that are forwarded to the current state
                Debug.Assert(tracker.TrackedStateMachines != null, "tracker.TrackedStateMachines != null");
                Assert.AreEqual(1, tracker.TrackedStateMachines.Count);
                Assert.AreEqual("State1", tracker.PreviousState);
                Debug.Assert(tracker.Transitions != null, "tracker.Transitions != null");
                Assert.AreEqual(2, tracker.Transitions.Count);
                Assert.AreEqual("T3, T5", tracker.PossibleTransitions);

                // Resume bookmark T5 and run until complete
                Assert.IsInstanceOfType(
                    host.TestWorkflowApplication.ResumeEpisodeBookmark("T5", null),
                    typeof(WorkflowCompletedEpisodeResult));

                Assert.AreEqual(1, tracker.TrackedStateMachines.Count);
            }
            finally
            {
                tracker.Trace();
                Debug.Assert(host.Tracking != null, "host.Tracking != null");
                host.Tracking.Trace();
            }
        }
        public void TrackerShouldConvertToAndFromXml()
        {
            var activity = new StateMachineExample();
            var host = WorkflowApplicationTest.Create(activity);
            var tracker1 = new StateMachineStateTracker(activity);
            Debug.Assert(host != null, "host != null");
            Debug.Assert(host.Extensions != null, "host.Extensions != null");
            host.Extensions.Add(tracker1);

            try
            {
                host.TestWorkflowApplication.RunEpisode("T1", Constants.Timeout);
                host.TestWorkflowApplication.ResumeEpisodeBookmark("T1", null, "T3");

                var xml = tracker1.ToXml();

                WorkflowTrace.Information("*** Tracker1***");
                WorkflowTrace.Information(xml);
                WorkflowTrace.Information(Environment.NewLine);

                var tracker2 = StateMachineStateTracker.Parse(activity, xml);
                WorkflowTrace.Information("*** Tracker2***");
                WorkflowTrace.Information(tracker2.ToXml());
                WorkflowTrace.Information(Environment.NewLine);

                Assert.AreEqual(tracker1.CurrentState, tracker2.CurrentState);
                Assert.AreEqual(tracker1.CurrentStateMachine, tracker2.CurrentStateMachine);
                Assert.AreEqual(tracker1.InstanceId, tracker2.InstanceId);
                Assert.AreEqual(tracker1.PossibleTransitions, tracker2.PossibleTransitions);
                Assert.AreEqual(tracker1.PreviousState, tracker2.PreviousState);
                Assert.AreEqual(tracker1.PreviousStateMachine, tracker2.PreviousStateMachine);
                Assert.AreEqual(tracker1.RootActivity, tracker2.RootActivity);
                AssertHelper.AreEqual(tracker1.StateHistory, tracker2.StateHistory);
                AssertHelper.AreEqual(tracker1.Transitions, tracker2.Transitions);
            }
            finally
            {
                host.Tracking.Trace();
            }
        }
        public void TrackerAccumulatesHistoryAcrossLoad()
        {
            using (var testdb = new SqlWorkflowInstanceStoreTest())
            {
                // Arrange
                var triggers = new[] { ExampleTrigger.T1 };
                var activity = new StateMachineExample();
                var host = WorkflowApplicationTest.Create(activity);
                Guid id;
                StateMachineStateTracker.Attach(host.TestWorkflowApplication, testdb.CreateInstanceStore());

                // Act
                using (host)
                {
                    try
                    {
                        // Start the workflow and run until it becomes idle with at least one bookmark
                        host.TestWorkflowApplication.RunEpisode(AnyBookmark, Constants.Timeout);

                        // Play each of the triggers
                        foreach (var trigger in triggers)
                        {
                            // Resume the workflow and run until any bookmark
                            host.TestWorkflowApplication.ResumeEpisodeBookmark(
                                trigger.ToString(), Constants.Timeout, AnyBookmark);
                        }

                        host.Persist(Constants.Timeout);
                        host.Unload(Constants.Timeout);
                        id = host.Id;

                    }
                    finally
                    {
                        host.Tracking.Trace();
                    }
                }

                var tracker = StateMachineStateTracker.LoadInstance(id, activity, testdb.ConnectionString);
                var host2 = WorkflowApplicationTest.Create(activity);
                StateMachineStateTracker.Attach(host2.TestWorkflowApplication, testdb.InstanceStore, tracker: tracker);
                host2.Load(id, Constants.Timeout);
                using (host2)
                {
                    try
                    {
                        // Resume the workflow and run until any bookmark
                        host2.TestWorkflowApplication.ResumeEpisodeBookmark(
                            ExampleTrigger.T3.ToString(), Constants.Timeout, AnyBookmark);

                    }
                    finally
                    {
                        host.Tracking.Trace();
                    }
                }

                // Assert
                Assert.IsNotNull(tracker);
                Assert.AreEqual(3, tracker.StateHistory.Count);
            }
        }
        public void HistoryIsCircularBuffer()
        {
            // Arrange
            const int MaxHistory = 3;
            var activity = new StateMachineExample();
            var host = WorkflowApplicationTest.Create(activity);
            var tracker = new StateMachineStateTracker(activity, MaxHistory);
            host.Extensions.Add(tracker);

            try
            {
                // Start the workflow - run to State1 with bookmark "T1"
                host.TestWorkflowApplication.RunEpisode("T1", Constants.Timeout);

                // History
                // State1
                CollectionAssert.AreEqual(tracker.StateHistory.ToList(), new[] { "State1" });

                // Run until State2 with bookmark "T3"
                host.TestWorkflowApplication.ResumeEpisodeBookmark("T1", null, "T3");

                // History
                // State1
                // State2
                CollectionAssert.AreEqual(tracker.StateHistory.ToList(), new[] { "State1", "State2" });

                // Run until State1 with bookmark "T1"
                host.TestWorkflowApplication.ResumeEpisodeBookmark("T3", null, "T1");

                // History
                // State1
                // State2
                // State1
                CollectionAssert.AreEqual(tracker.StateHistory.ToList(), new[] { "State1", "State2", "State1" });

                // Run until State2 with bookmark "T3"
                host.TestWorkflowApplication.ResumeEpisodeBookmark("T1", null, "T3");

                // History
                // State1 <- Dropped from buffer
                // State2
                // State1
                // State2
                Assert.AreEqual(MaxHistory, tracker.StateHistory.Count());
                CollectionAssert.AreEqual(tracker.StateHistory.ToList(), new[] { "State2", "State1", "State2" });
            }
            finally
            {
                tracker.Trace();
                Debug.Assert(host.Tracking != null, "host.Tracking != null");
                host.Tracking.Trace();
            }
        }
        /// <summary>
        ///   Runs the sample state machine through a number of triggers and leaves a persisted instance
        /// </summary>
        /// <param name="testdb"> The test database </param>
        /// <param name="triggers"> The triggers </param>
        /// <returns> The workflow instance ID </returns>
        private Guid RunSampleStateMachine(SqlWorkflowInstanceStoreTest testdb, params ExampleTrigger[] triggers)
        {
            var activity = new StateMachineExample();
            var host = WorkflowApplicationTest.Create(activity);
            Debug.Assert(host != null, "host != null");
            Debug.Assert(testdb != null, "TestInstanceStore != null");
            StateMachineStateTracker.Attach(
                host.TestWorkflowApplication, new SqlWorkflowInstanceStore(testdb.ConnectionString));
            using (host)
            {
                try
                {
                    // Start the workflow and run until it becomes idle with at least one bookmark
                    Assert.IsInstanceOfType(
                        host.TestWorkflowApplication.RunEpisode(AnyBookmark, Constants.Timeout),
                        typeof(WorkflowIdleEpisodeResult));

                    // Play each of the triggers
                    Debug.Assert(triggers != null, "triggers != null");
                    foreach (var trigger in triggers)
                    {
                        // Resume the workflow and run until any bookmark
                        host.TestWorkflowApplication.ResumeEpisodeBookmark(
                            trigger.ToString(), Constants.Timeout, AnyBookmark);
                    }

                    host.Persist(Constants.Timeout);
                    host.Unload(Constants.Timeout);
                }
                finally
                {
                    Debug.Assert(host.Tracking != null, "host.Tracking != null");
                    host.Tracking.Trace();
                }
            }

            return host.Id;
        }