public void AnyActivityInstanceStateFindsClosed()
        {
            // Arrange
            var activity = new AddToNumOrThrow();
            dynamic args = new WorkflowArguments();
            args.Num = 2;
            var host = new WorkflowApplication(activity, args);
            var tracking = new ListTrackingParticipant();
            host.Extensions.Add(tracking);

            try
            {
                host.RunEpisode();

                // Act
                var any = tracking.Records.Any(ActivityInstanceState.Closed);

                // Assert
                Assert.IsTrue(any);
            }
            finally
            {
                tracking.Trace();
            }
        }
        public void AssertWillReturnAnAssertHostTracking()
        {
            var activity = CreateTestActivity();
            var host = new WorkflowApplication(activity);
            var target = new MemoryTrackingParticipant();
            host.Extensions.Add(target);

            host.RunEpisode();

            Assert.IsNotNull(target.Assert);
            Assert.IsInstanceOfType(target.Assert, typeof(MemoryTrackingParticipant.AssertHostTracking));
        }
        public void GetExtensionsReturnsExtensionsCollection()
        {
            const string BookmarkName = "Test";

            var activity = new Sequence
                {
                    Activities =
                        {
                            new ActivityExtensionTest { AddExtensionProvider = true },
                            new TestBookmark<int> { BookmarkName = BookmarkName },
                            new ActivityExtensionTest { AddExtensionProvider = true },
                        }
                };

            var traceTrackingParticipant = new TraceTrackingParticipant();
            var listTrackingParticipant = new ListTrackingParticipant();

            var workflowApplication = new WorkflowApplication(activity);

            // Add a couple of singleton extensions
            workflowApplication.Extensions.Add(traceTrackingParticipant);
            workflowApplication.Extensions.Add(listTrackingParticipant);

            // foreach (var extension in workflowApplication.Extensions)
            // {
            // Doh! this won't work
            // foreach statement cannot operate on variables of type
            // 'System.Activities.Hosting.WorkflowInstanceExtensionManager'
            // because 'System.Activities.Hosting.WorkflowInstanceExtensionManager'
            // does not contain a public definition for 'GetEnumerator'
            // }

            // Run it so that the activity will create an extension
            workflowApplication.RunEpisode(BookmarkName, Constants.Timeout);

            // Resume and run to completion
            workflowApplication.ResumeEpisodeBookmark(BookmarkName, 1);

            // Now I can get the Singleton Extensions as a collection
            var extensions = workflowApplication.GetSingletonExtensions();
            Assert.IsNotNull(extensions);
            Assert.AreEqual(2, extensions.Count);

            // Note: Extensions created by AddDefaultExtensionProvider will not appear in the collection
            Assert.IsTrue(extensions.Contains(traceTrackingParticipant));
            Assert.IsTrue(extensions.Contains(listTrackingParticipant));

            foreach (var extension in extensions)
            {
                Debug.WriteLine("Found singleton extension " + extension);
            }
        }
        public void TraceTrackingParticipantShouldTrace()
        {
            // Arrange
            var target = new TraceTrackingParticipant();
            var host = new WorkflowApplication(new Sequence());
            host.Extensions.Add(target);
            var memoryListener = new MemoryListener();
            Trace.Listeners.Add(memoryListener);

            // Act
            host.RunEpisode();

            Assert.IsTrue(memoryListener.Records.Count > 0);
        }
        public void WhenIdleWithBookmarkContainsBookmarkShouldReturnTrueOnMatch()
        {
            const string Expected = "TestBookmark";
            var found = false;

            var activity = new Sequence
                {
                   Activities = {
                                     new TestBookmark<int> { BookmarkName = Expected }, new WriteLine()
                                 }
                };

            var host = new WorkflowApplication(activity) { Idle = args => found = args.ContainsBookmark(Expected) };

            // Run the workflow until idle with the bookmark
            var result = host.RunEpisode(Expected, TimeSpan.FromMilliseconds(100));

            Assert.IsNotNull(result);
            Assert.IsInstanceOfType(result, typeof(WorkflowIdleEpisodeResult));
            Assert.AreEqual(ActivityInstanceState.Executing, result.State);
            Assert.IsTrue(found);
        }
        public void WhenPersistedInstanceLoadedRunEpisodeShouldComplete()
        {
            var activity = new TestBookmark<int> { BookmarkName = "Test" };

            var workflowApplication = new WorkflowApplication(activity)
                {
                   InstanceStore = new MemoryStore(), PersistableIdle = args => PersistableIdleAction.Unload,
                };

            // Episodes can end with until unloaded, aborted, completed, timeout
            // Run episode until unloaded because of persistable idle event
            var workflowIdleEpisodeResult =
                workflowApplication.RunEpisode(Constants.Timeout) as WorkflowIdleEpisodeResult;

            Assert.IsNotNull(workflowIdleEpisodeResult);

            // Cannot resume the same WorkflowApplication - it will cause a System.InvalidOperationException
            // Message=WorkflowInstance (guid) cannot be modified after it has started running.
            var workflowApplicationResume = new WorkflowApplication(activity) { InstanceStore = new MemoryStore(), };

            // Load the instance with a new WorkflowApplication
            workflowApplicationResume.Load(workflowIdleEpisodeResult.InstanceId);

            // Resume and complete
            var result = workflowApplicationResume.ResumeEpisodeBookmark("Test", 1);

            Assert.IsInstanceOfType(result, typeof(WorkflowCompletedEpisodeResult));
            Assert.AreEqual(ActivityInstanceState.Closed, result.State);
            AssertOutArgument.AreEqual(((WorkflowCompletedEpisodeResult)result).Outputs, "Result", 1);
        }
        public void FirstOrDefaultActivityInstanceStateDoesNotFindFaulted()
        {
            // Arrange
            var activity = new AddToNumOrThrow();
            dynamic args = new WorkflowArguments();
            args.Num = 2;
            var host = new WorkflowApplication(activity, args);
            var tracking = new ListTrackingParticipant();
            host.Extensions.Add(tracking);

            host.RunEpisode();

            // Act
            var record = tracking.Records.FirstOrDefault(ActivityInstanceState.Faulted);

            // Assert
            Assert.IsNull(record);
        }
        public void AttachToInitializedWorkflowApplicationShouldThrow()
        {
            using (var testdb = new SqlWorkflowInstanceStoreTest())
            {
                // Arrange
                var host = new WorkflowApplication(new TestBookmark<int> { BookmarkName = "B1" });
                var store = testdb.CreateInstanceStore();
                host.RunEpisode("B1");

                // Act / Assert
                AssertHelper.Throws<InvalidOperationException>(() => StateMachineStateTracker.Attach(host, store));
            }
        }
        public void WhenIdleWithNoBookmarksContainsBookmarkShouldReturnFalseOnNoMatch()
        {
            var found = false;

            var activity = new Sequence { Activities = { new TestAsync { Sleep = 10 }, new WriteLine() } };

            var host = new WorkflowApplication(activity)
                {
                   Idle = args => found = args.ContainsBookmark("No Bookmarks Should Match")
                };

            host.RunEpisode(TimeSpan.FromMilliseconds(50000));

            Assert.IsFalse(found);
        }
        public void RecordsWillReturnTrackingRecordList()
        {
            var activity = CreateTestActivity();
            var host = new WorkflowApplication(activity);
            var target = new MemoryTrackingParticipant();
            host.Extensions.Add(target);

            host.RunEpisode();

            Assert.IsNotNull(target.Records);
            Assert.IsInstanceOfType(target.Records, typeof(TrackingRecordsList));
        }
        public void TraceWillTraceRecords()
        {
            // Arrange
            var activity = CreateTestActivity();
            var host = new WorkflowApplication(activity);
            var target = new MemoryTrackingParticipant();
            host.Extensions.Add(target);
            var listener = new TestTraceListener();

            Trace.Listeners.Add(listener);

            // Act
            host.RunEpisode();
            target.Trace();

            // Assert
            Assert.IsTrue(listener.WriteLineCount > 0);
        }
        public void FirstThrowsNegStartRecordNumber()
        {
            // Arrange
            const string DisplayName = "Assign";
            const long StartRecordNumber = -1;
            var activity = new AddToNumOrThrow();
            dynamic args = new WorkflowArguments();
            args.Num = 2;
            var host = new WorkflowApplication(activity, args);
            var tracking = new ListTrackingParticipant();
            host.Extensions.Add(tracking);

            try
            {
                host.RunEpisode();

                // Act / Assert
                AssertHelper.Throws<ArgumentOutOfRangeException>(
                    () =>
                    tracking.Records.First(
                        ActivityInstanceState.Executing, DisplayName, startRecordNumber: StartRecordNumber));
            }
            finally
            {
                tracking.Trace();
            }
        }
        public void WhereIdAndStartRecordNumber()
        {
            // Arrange
            const string Id = "1.9";
            const long StartRecordNumber = 5;
            var activity = new AddToNumOrThrow();
            dynamic args = new WorkflowArguments();
            args.Num = 2;
            var host = new WorkflowApplication(activity, args);
            var tracking = new ListTrackingParticipant();
            host.Extensions.Add(tracking);

            try
            {
                host.RunEpisode();

                // Act
                var query = tracking.Records.Where(
                    ActivityInstanceState.Executing, activityId: Id, startRecordNumber: StartRecordNumber);

                // Assert
                var list = query.ToList();
                Assert.AreEqual(1, list.Count());
                var activityStateRecord = list.FirstOrDefault();
                Assert.IsNotNull(activityStateRecord);
                Assert.AreEqual(Id, activityStateRecord.Activity.Id);
                Assert.AreEqual(ActivityInstanceState.Executing, activityStateRecord.GetInstanceState());
            }
            finally
            {
                tracking.Trace();
            }
        }
        public void WhereDisplayNameMatch()
        {
            // Arrange
            const string DisplayName = "AddToNumOrThrow";
            var activity = new AddToNumOrThrow();
            dynamic args = new WorkflowArguments();
            args.Num = 2;
            var host = new WorkflowApplication(activity, args);
            var tracking = new ListTrackingParticipant();
            host.Extensions.Add(tracking);

            try
            {
                host.RunEpisode();

                // Act
                var query = tracking.Records.Where(ActivityInstanceState.Executing, DisplayName);

                // Assert
                var list = query.ToList();
                Assert.AreEqual(1, list.Count());
                var activityStateRecord = list.FirstOrDefault();
                Assert.IsNotNull(activityStateRecord);
                Assert.AreEqual(DisplayName, activityStateRecord.Activity.Name);
                Assert.AreEqual(ActivityInstanceState.Executing, activityStateRecord.GetInstanceState());
            }
            finally
            {
                tracking.Trace();
            }
        }
        public void WhereActivityInstanceStateFindsClosed()
        {
            // Arrange
            var activity = new AddToNumOrThrow();
            dynamic args = new WorkflowArguments();
            args.Num = 2;
            var host = new WorkflowApplication(activity, args);
            var tracking = new ListTrackingParticipant();
            host.Extensions.Add(tracking);

            try
            {
                host.RunEpisode();

                // Act
                var query = tracking.Records.Where(ActivityInstanceState.Closed);

                // Assert
                var list = query.ToList();
                Assert.AreEqual(4, list.Count());
                Assert.IsFalse(
                    list.Any(record => record != null && record.GetInstanceState() != ActivityInstanceState.Closed),
                    "Found record where the state is not closed");
            }
            finally
            {
                tracking.Trace();
            }
        }
        public void WhereActivityInstanceStateDoesNotFindFaulted()
        {
            // Arrange
            var activity = new AddToNumOrThrow();
            dynamic args = new WorkflowArguments();
            args.Num = 2;
            var host = new WorkflowApplication(activity, args);
            var tracking = new ListTrackingParticipant();
            host.Extensions.Add(tracking);

            try
            {
                host.RunEpisode();

                // Act
                var query = tracking.Records.Where(ActivityInstanceState.Faulted);

                // Assert
                Assert.AreEqual(0, query.Count());
            }
            finally
            {
                tracking.Trace();
            }
        }
        public void AnyDisplayNameMatchWithStartRecordNumber()
        {
            // Arrange
            const string DisplayName = "Assign";
            const string Id = "1.9";
            const long StartRecordNumber = 5;
            var activity = new AddToNumOrThrow();
            dynamic args = new WorkflowArguments();
            args.Num = 2;
            var host = new WorkflowApplication(activity, args);
            var tracking = new ListTrackingParticipant();
            host.Extensions.Add(tracking);

            try
            {
                host.RunEpisode();

                // Act
                var any = tracking.Records.Any(ActivityInstanceState.Executing, DisplayName, Id, StartRecordNumber);

                // Assert
                Assert.IsTrue(any);
            }
            finally
            {
                tracking.Trace();
            }
        }
        public void SingleOrDefaultActivityInstanceStateThrowsOnClosed()
        {
            // Arrange
            var activity = new AddToNumOrThrow();
            dynamic args = new WorkflowArguments();
            args.Num = 2;
            var host = new WorkflowApplication(activity, args);
            var tracking = new ListTrackingParticipant();
            host.Extensions.Add(tracking);

            try
            {
                host.RunEpisode();

                // Act / Assert
                AssertHelper.Throws<InvalidOperationException>(
                    () => tracking.Records.SingleOrDefault(ActivityInstanceState.Closed));
            }
            finally
            {
                tracking.Trace();
            }
        }
        public void SingleDisplayNameMatchWithStartRecordNumber()
        {
            // Arrange
            const string DisplayName = "Assign";
            const long StartRecordNumber = 5;
            var activity = new AddToNumOrThrow();
            dynamic args = new WorkflowArguments();
            args.Num = 2;
            var host = new WorkflowApplication(activity, args);
            var tracking = new ListTrackingParticipant();
            host.Extensions.Add(tracking);

            try
            {
                host.RunEpisode();

                // Act
                var record = tracking.Records.Single(
                    ActivityInstanceState.Executing, DisplayName, startRecordNumber: StartRecordNumber);

                // Assert
                Assert.IsNotNull(record);
                Assert.AreEqual(ActivityInstanceState.Executing, record.GetInstanceState());
            }
            finally
            {
                tracking.Trace();
            }
        }
        public void FirstOrDefaultDisplayNameNoMatchPastStartRecordNumber()
        {
            // Arrange
            const string DisplayName = "Assign";
            const long StartRecordNumber = 9;
            var activity = new AddToNumOrThrow();
            dynamic args = new WorkflowArguments();
            args.Num = 2;
            var host = new WorkflowApplication(activity, args);
            var tracking = new ListTrackingParticipant();
            host.Extensions.Add(tracking);

            try
            {
                host.RunEpisode();

                // Act
                var record = tracking.Records.FirstOrDefault(
                    ActivityInstanceState.Executing, DisplayName, startRecordNumber: StartRecordNumber);

                // Assert
                Assert.IsNull(record);
            }
            finally
            {
                tracking.Trace();
            }
        }
        public void FirstOrDefaultIdMatch()
        {
            // Arrange
            const string Id = "1";
            var activity = new AddToNumOrThrow();
            dynamic args = new WorkflowArguments();
            args.Num = 2;
            var host = new WorkflowApplication(activity, args);
            var tracking = new ListTrackingParticipant();
            host.Extensions.Add(tracking);

            try
            {
                host.RunEpisode();

                // Act
                var record = tracking.Records.FirstOrDefault(ActivityInstanceState.Executing, activityId: Id);

                // Assert
                Assert.IsNotNull(record);
                Assert.AreEqual(ActivityInstanceState.Executing, record.GetInstanceState());
            }
            finally
            {
                tracking.Trace();
            }
        }
        public void WhereIdNoMatchPastStartRecordNumber()
        {
            // Arrange
            const string Id = "Assign";
            const long StartRecordNumber = 9;
            var activity = new AddToNumOrThrow();
            dynamic args = new WorkflowArguments();
            args.Num = 2;
            var host = new WorkflowApplication(activity, args);
            var tracking = new ListTrackingParticipant();
            host.Extensions.Add(tracking);

            try
            {
                host.RunEpisode();

                // Act
                var query = tracking.Records.Where(
                    ActivityInstanceState.Executing, activityId: Id, startRecordNumber: StartRecordNumber);

                // Assert
                var list = query.ToList();
                Assert.AreEqual(0, list.Count());
            }
            finally
            {
                tracking.Trace();
            }
        }
        public void LastActivityInstanceStateDoesNotFindFaulted()
        {
            // Arrange
            var activity = new AddToNumOrThrow();
            dynamic args = new WorkflowArguments();
            args.Num = 2;
            var host = new WorkflowApplication(activity, args);
            var tracking = new ListTrackingParticipant();
            host.Extensions.Add(tracking);

            host.RunEpisode();

            // Act / Assert
            AssertHelper.Throws<InvalidOperationException>(() => tracking.Records.Last(ActivityInstanceState.Faulted));
        }
        public void WithArgumentValueMatch()
        {
            // Arrange
            const string DisplayName = "AddToNumOrThrow";
            var activity = new AddToNumOrThrow();
            dynamic args = new WorkflowArguments();
            args.Num = 2;
            var host = new WorkflowApplication(activity, args);
            var tracking = new ListTrackingParticipant();
            host.Extensions.Add(tracking);

            try
            {
                host.RunEpisode();

                // Act
                var query = tracking.Records.OfType<ActivityStateRecord>().WithArgument("Num", 2);

                // Assert
                var list = query.ToList();
                Assert.AreEqual(2, list.Count());
                var first = list.First();
                Assert.IsNotNull(first);
                Assert.AreEqual(DisplayName, first.Activity.Name);
                Assert.AreEqual(ActivityInstanceState.Executing, first.GetInstanceState());
                var last = list.Last();
                Assert.IsNotNull(last);
                Assert.AreEqual(DisplayName, last.Activity.Name);
                Assert.AreEqual(ActivityInstanceState.Closed, last.GetInstanceState());
            }
            finally
            {
                tracking.Trace();
            }
        }
        public void WhenNotAbortedIsAbortedIsFalse()
        {
            const string BookmarkName = "Test";

            var activity = new TestBookmark<int> { BookmarkName = BookmarkName };

            var workflowApplication = new WorkflowApplication(activity);

            workflowApplication.RunEpisode(BookmarkName, Constants.Timeout);

            Assert.IsFalse(workflowApplication.IsAborted());
        }
        public void WhenNoBookmarksAndOutArgRunShouldCompleteWithOutArgs()
        {
            const int Expected = 1;
            var workflowApplication = new WorkflowApplication(new EchoArg<int> { Value = Expected });

            // To run it synchronously
            var result = workflowApplication.RunEpisode(Constants.Timeout);

            // Or asynchronously using a Task
            // var result = workflowApplication.RunEpisodeAsync(this.DefaultTimeout).Result;
            Assert.IsInstanceOfType(result, typeof(WorkflowCompletedEpisodeResult));

            var completedResult = (WorkflowCompletedEpisodeResult)result;
            Assert.AreEqual(ActivityInstanceState.Closed, completedResult.State);
            AssertOutArgument.AreEqual(completedResult.Outputs, "Result", Expected);
        }
        public void WithVariableValueThrowsNegStartRecordNumber()
        {
            // Arrange
            const long StartRecordNumber = -1;
            var activity = new AddToNumOrThrow();
            dynamic args = new WorkflowArguments();
            args.Num = 2;
            var host = new WorkflowApplication(activity, args);
            var tracking = new ListTrackingParticipant();
            host.Extensions.Add(tracking);

            try
            {
                host.RunEpisode();

                // Act / Assert
                AssertHelper.Throws<ArgumentOutOfRangeException>(
                    () => tracking.Records.OfType<ActivityStateRecord>().WithVariable("BAD", 1, StartRecordNumber));
            }
            finally
            {
                tracking.Trace();
            }
        }
        public void FirstActivityInstanceStateFindsClosed()
        {
            // Arrange
            var activity = new AddToNumOrThrow();
            dynamic args = new WorkflowArguments();
            args.Num = 2;
            var host = new WorkflowApplication(activity, args);
            var tracking = new ListTrackingParticipant();
            host.Extensions.Add(tracking);

            try
            {
                host.RunEpisode();

                // Act
                var record = tracking.Records.First(ActivityInstanceState.Closed);

                // Assert
                Assert.IsNotNull(record);
                Assert.AreEqual(ActivityInstanceState.Closed, record.GetInstanceState());
            }
            finally
            {
                tracking.Trace();
            }
        }
        public void WithVariableValueStartMatch()
        {
            // Arrange
            const string DisplayName = "Sequence";
            var activity = new AddToNumOrThrow();
            dynamic args = new WorkflowArguments();
            args.Num = 2;
            var host = new WorkflowApplication(activity, args);
            var tracking = new ListTrackingParticipant();
            host.Extensions.Add(tracking);

            try
            {
                host.RunEpisode();

                // Act
                // Find all ActivityStateRecords that have an variable named "Num" starting with record 7
                var query = tracking.Records.OfType<ActivityStateRecord>().WithVariable("VarNum", 1, 7);

                // Assert
                var list = query.ToList();
                Assert.AreEqual(1, list.Count());
                var first = list.First();
                Assert.IsNotNull(first);
                Assert.AreEqual(DisplayName, first.Activity.Name);
                Assert.AreEqual(ActivityInstanceState.Closed, first.GetInstanceState());
            }
            finally
            {
                tracking.Trace();
            }
        }
        public void WhenstringleWithPersistenceUnloadRunShouldReturnIdleUnloaded()
        {
            var activity = new TestBookmark<int> { BookmarkName = "Test" };

            var workflowApplication = new WorkflowApplication(activity)
                {
                   InstanceStore = new MemoryStore(), PersistableIdle = args => PersistableIdleAction.Unload,
                };

            // Episodes can end with until unloaded, aborted, completed, timeout
            // Run episode until unloaded because of persistable idle event
            var workflowIdleEpisodeResult =
                workflowApplication.RunEpisode(Constants.Timeout) as WorkflowIdleEpisodeResult;

            Assert.IsNotNull(workflowIdleEpisodeResult);
            Assert.AreEqual(ActivityInstanceState.Executing, workflowIdleEpisodeResult.State);
            Assert.IsTrue(workflowIdleEpisodeResult.Unloaded);
        }