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 TestMethod1()
        {
            // Arrange
            WorkflowTestTrace.Arrange();
            var activity = new FileReadToEnd() { FileName = Constants.Workflow1Xaml };
            var tracking = new ListTrackingParticipant();
            var workflow = new Workflow(activity) { Tracking = tracking };

            try
            {
                // Act
                WorkflowTestTrace.Act();
                var result = workflow.Start().Result.Output.Result;

                // Assert
                WorkflowTestTrace.Assert();

                Assert.AreEqual(2113, result.Length);
            }
            finally
            {
                WorkflowTestTrace.Finally();
                workflow.Trace();
            }
        }
        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 GetRecordNumberIncludedWhenOptionRecordNumber()
        {
            // Arrange
            var activity = new Sequence();
            var listTrackingParticipant = new ListTrackingParticipant();
            var host = new WorkflowInvokerTest(activity);
            host.Extensions.Add(listTrackingParticipant);
            host.TestActivity();
            var record = listTrackingParticipant.Records.First();

            try
            {
                // Act
                var actual = record.ToFormattedString(TrackingOption.RecordNumber);

                // Assert
                Assert.IsTrue(actual.StartsWith("0: "));
            }
            finally
            {
                listTrackingParticipant.Trace();
            }
        }
        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 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 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 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 CancelTaskAsyncActivityViaToken()
        {
            // Arrange
            TestTrace.Arrange();
            var spinExecuting = new ManualResetEvent(false);
            var completedEvent = new ManualResetEvent(false);
            var notify = new SpinNotify { LoopComplete = (loops, iterations) => spinExecuting.Set() };
            var cancellationHandlerClosed = new AutoResetEvent(false);
            var activity = CreateSequenceWithSpinWaiter(typeof(TaskSpinWaiter));

            var tracking = new ListTrackingParticipant();

            var workflow = new WorkflowP1(activity)
            {
                Timeout = Constants.Timeout,
                Extensions =
                        {
                            tracking, 
                            notify
                        }
            };

            workflow.When.Activity.Name("CancellationHandler").Closed +=
                (sender, args) => cancellationHandlerClosed.Set();

            workflow.When.Completed += (sender, args) => completedEvent.Set();

            var source = new CancellationTokenSource(Constants.Timeout);

            try
            {
                // Act
                TestTrace.Act();
                var task = workflow.RunAsync(source.Token);

                TestTrace.Write("Waiting for AsyncSpinWaiter to start executing");
                Assert.IsTrue(spinExecuting.WaitOne(Constants.Timeout));

                TestTrace.Write("Cancelling workflow with token");
                source.Cancel();

                TestTrace.Write("Waiting for workflow to execute cancellation handler");
                Assert.IsTrue(cancellationHandlerClosed.WaitOne(Constants.Timeout));

                TestTrace.Write("Waiting for workflow");

                // Assert
                TestTrace.Assert();
                AssertHelper.Throws<AggregateException>(task.Wait, typeof(TaskCanceledException));
                Assert.IsTrue(
                    tracking.Records.Any(ActivityInstanceState.Closed, "CancellationHandler"),
                    "The cancellation handler was not invoked");
                Assert.IsTrue(task.IsCanceled);
                Assert.IsTrue(task.IsCompleted);
            }
            finally
            {
                TestTrace.Finally();

                workflow.Trace();
            }
        }
        public void WorkflowServiceHostReturnsExtensionsCollection()
        {
            var traceTrackingParticipant = new TraceTrackingParticipant();
            var listTrackingParticipant = new ListTrackingParticipant();

            var service = new WorkflowService() { Body = new Sequence() };
            var host = new WorkflowServiceHost(service);

            // Add a couple of singleton extensions
            host.WorkflowExtensions.Add(traceTrackingParticipant);
            host.WorkflowExtensions.Add(listTrackingParticipant);

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

            Assert.IsTrue(extensions.Contains(traceTrackingParticipant));
            Assert.IsTrue(extensions.Contains(listTrackingParticipant));
        }
        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 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 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 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 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 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 ListTracingShouldFormatString()
        {
            // Arrange
            const string Expected = @"ListTrackingParticipant
            {
            0: WorkflowInstance ""Sequence"" is Started
            1: Activity [null] ""null"" scheduled child activity [1] ""Sequence""
            2: Activity [1] ""Sequence"" is Executing
            3: Activity [1] ""Sequence"" scheduled child activity [4] ""EchoArg<Int32>""
            4: Activity [4] ""EchoArg<Int32>"" is Executing
            {
            Arguments
            {
            Value: 123
            }
            }

            5: Activity [4] ""EchoArg<Int32>"" is Closed
            {
            Arguments
            {
            Value: 123
            Result: 123
            }
            }

            6: Activity [1] ""Sequence"" scheduled child activity [2] ""WaitForBookmark""
            7: Activity [2] ""WaitForBookmark"" is Executing
            {
            Arguments
            {
            BookmarkName: Test
            }
            }

            8: WorkflowInstance ""Sequence"" is Idle
            }
            ";

            WorkflowTrace.Information("Arrange");
            var activity = new Sequence
                {
                    Activities =
                        {
                            new EchoArg<int> { Value = new InArgument<int>(123) },
                            new WaitForBookmark { BookmarkName = "Test" },
                        }
                };
            var listTrackingParticipant = new ListTrackingParticipant();
            var workflow = WorkflowApplicationTest.Create(activity);
            workflow.Extensions.Add(listTrackingParticipant);
                // Act
                WorkflowTrace.Information("Act");

                // Run until idle with the Test extension
                workflow.TestWorkflowApplication.RunUntilBookmark("Test");
                var actual = listTrackingParticipant.ToFormattedString();

                // Assert
                Assert.AreEqual(Environment.NewLine + Expected, Environment.NewLine + actual);
        }
        public void CancelWithAsyncActivityWillCancel()
        {
            // Arrange
            TestTrace.Arrange();
            var spinExecuting = new AutoResetEvent(false);
            var notify = new SpinNotify { LoopComplete = (loops, iterations) => spinExecuting.Set() };
            var cancellationHandlerClosed = new AutoResetEvent(false);
            var activity = CreateSequenceWithSpinWaiter(typeof(AsyncSpinWaiter));

            var tracking = new ListTrackingParticipant();

            var workflow = new WorkflowP1(activity)
            {
                Timeout = Constants.Timeout,
                Extensions =
                        {
                            tracking, 
                            notify
                        }
            };

            workflow.When.Activity.Name("CancellationHandler").Closed +=
                (sender, args) => cancellationHandlerClosed.Set();

            var source = new CancellationTokenSource(Constants.Timeout);

            try
            {
                // Act
                TestTrace.Act();
                workflow.Until.Idle.RunAsync(source.Token);

                TestTrace.Write("Waiting for AsyncSpinWaiter to start executing");
                var spinWait = spinExecuting.WaitOne(TimeSpan.FromSeconds(10));

                TestTrace.Write("Cancelling workflow");
                source.Cancel();

                var cancelInvoked = cancellationHandlerClosed.WaitOne(Constants.Timeout);

                // Assert
                TestTrace.Assert();
                Assert.IsTrue(spinWait, "The spinExecuting event was not set");
                Assert.IsTrue(cancelInvoked);
                Assert.IsTrue(
                    tracking.Records.Any(ActivityInstanceState.Closed, "CancellationHandler"),
                    "The cancellation handler was not invoked");
            }
            finally
            {
                TestTrace.Finally();

                workflow.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 CancelWorkflowApp()
        {
            // Arrange
            TestTrace.Arrange();
            var spinExecuting = new AutoResetEvent(false);
            var completed = new AutoResetEvent(false);
            var notify = new SpinNotify { LoopComplete = (loops, iterations) => spinExecuting.Set() };
            var activity = CreateSequenceWithSpinWaiter(typeof(SpinWaiter));

            WorkflowApplicationCompletedEventArgs completedArgs = null;

            var workflowApplication = new WorkflowApplication(activity)
                {
                    Completed = args =>
                        {
                            completedArgs = args;
                            WorkflowTrace.Verbose(
                                "Completed state: {0} fault {1}", args.CompletionState, args.TerminationException);
                            completed.Set();
                        },
                    Aborted = args => WorkflowTrace.Verbose("Aborted {0}", args.Reason),
                };

            var source = new CancellationTokenSource(Constants.Timeout);

            var tracking = new ListTrackingParticipant();
            workflowApplication.Extensions.Add(tracking);
            workflowApplication.Extensions.Add(notify);
            var activitySource = new ActivityCancellationToken(source.Token);
            workflowApplication.Extensions.Add(activitySource);

            try
            {
                // Act
                TestTrace.Act();

                workflowApplication.Run();

                TestTrace.Write("Waiting for AsyncSpinWaiter to start executing");
                var spinWait = spinExecuting.WaitOne(TimeSpan.FromSeconds(10));

                if (spinWait)
                {
                    source.Token.Register(workflowApplication.Cancel);

                    TestTrace.Write("Cancelling workflow");
                    source.Cancel();

                    // workflow.Cancel();
                }
                else
                {
                    TestTrace.Write("spinWait timeout");
                }

                var isComplete = completed.WaitOne(Constants.Timeout);

                // Assert
                TestTrace.Assert();

                Assert.IsTrue(isComplete);
                Assert.IsNotNull(completedArgs);
                Assert.AreEqual(ActivityInstanceState.Canceled, completedArgs.CompletionState);
            }
            finally
            {
                TestTrace.Finally();
                tracking.Trace();
            }
        }
        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 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 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();
            }
        }