Example #1
0
        public void Sched_Task_TplFifoTest_TaskScheduler()
        {
            UnitTestSchedulingContext cntx                = new UnitTestSchedulingContext();
            OrleansTaskScheduler      scheduler           = TestInternalHelper.InitializeSchedulerForTesting(cntx);
            ActivationTaskScheduler   activationScheduler = scheduler.GetWorkItemGroup(cntx).TaskRunner;

            int n = 0;

            // ReSharper disable AccessToModifiedClosure
            Task task1 = new Task(() => { Thread.Sleep(1000); n = n + 5; });
            Task task2 = new Task(() => { n = n * 3; });

            // ReSharper restore AccessToModifiedClosure

            // By queuuing to ActivationTaskScheduler we guarantee single threaded ordered execution.
            // If we queued to OrleansTaskScheduler we would not guarantee that.
            task1.Start(activationScheduler);
            task2.Start(activationScheduler);

            // Pause to let things run
            Thread.Sleep(TimeSpan.FromSeconds(2));

            // N should be 15, because the two tasks should execute in order
            Assert.IsTrue(n != 0, "Work items did not get executed");
            Assert.AreEqual(15, n, "Work items executed out of order");
        }
Example #2
0
        /// <summary> Return dump of diagnostic data from this silo. </summary>
        /// <param name="all"></param>
        /// <returns>Debug data for this silo.</returns>
        public string GetDebugDump(bool all = true)
        {
            var sb = new StringBuilder();

            foreach (var sytemTarget in activationDirectory.AllSystemTargets())
            {
                sb.AppendFormat("System target {0}:", sytemTarget.GrainId.ToString()).AppendLine();
            }

            var enumerator = activationDirectory.GetEnumerator();

            while (enumerator.MoveNext())
            {
                var activationData = enumerator.Current.Value;
                var workItemGroup  = scheduler.GetWorkItemGroup(new SchedulingContext(activationData));
                if (workItemGroup == null)
                {
                    sb.AppendFormat("Activation with no work item group!! Grain {0}, activation {1}.", activationData.Grain,
                                    activationData.ActivationId);
                    sb.AppendLine();
                    continue;
                }

                if (all || activationData.IsUsable)
                {
                    sb.AppendLine(workItemGroup.DumpStatus());
                    sb.AppendLine(activationData.DumpStatus());
                }
            }
            logger.Info(ErrorCode.SiloDebugDump, sb.ToString());
            return(sb.ToString());
        }
Example #3
0
        public void Sched_Task_TplFifoTest()
        {
            // This is not a great test because there's a 50/50 shot that it will work even if the scheduling
            // is completely and thoroughly broken and both closures are executed "simultaneously"
            UnitTestSchedulingContext context = new UnitTestSchedulingContext();
            OrleansTaskScheduler      orleansTaskScheduler = TestInternalHelper.InitializeSchedulerForTesting(context);
            ActivationTaskScheduler   scheduler            = orleansTaskScheduler.GetWorkItemGroup(context).TaskRunner;

            int n = 0;

            // ReSharper disable AccessToModifiedClosure
            Task task1 = new Task(() => { Thread.Sleep(1000); n = n + 5; });
            Task task2 = new Task(() => { n = n * 3; });

            // ReSharper restore AccessToModifiedClosure

            task1.Start(scheduler);
            task2.Start(scheduler);

            // Pause to let things run
            Thread.Sleep(2000);

            // N should be 15, because the two tasks should execute in order
            Assert.IsTrue(n != 0, "Work items did not get executed");
            Assert.AreEqual(15, n, "Work items executed out of order");
            Console.WriteLine("Test executed OK.");
            orleansTaskScheduler.Stop();
        }
Example #4
0
        public async Task OrleansSched_Test1_Bounce()
        {
            UnitTestSchedulingContext context = new UnitTestSchedulingContext();
            OrleansTaskScheduler      orleansTaskScheduler = TestInternalHelper.InitializeSchedulerForTesting(context);
            ActivationTaskScheduler   scheduler            = orleansTaskScheduler.GetWorkItemGroup(context).TaskRunner;

            await Run_ActivationSched_Test1(scheduler, true);
        }
Example #5
0
        public async Task OrleansSched_Test1()
        {
            UnitTestSchedulingContext context = new UnitTestSchedulingContext();
            OrleansTaskScheduler      orleansTaskScheduler = TestInternalHelper.InitializeSchedulerForTesting(context, this.loggerFactory);
            ActivationTaskScheduler   scheduler            = orleansTaskScheduler.GetWorkItemGroup(context).TaskScheduler;

            await Run_ActivationSched_Test1(scheduler, false);
        }
Example #6
0
        public void Async_Task_Start_ActivationTaskScheduler()
        {
            ActivationTaskScheduler activationScheduler = scheduler.GetWorkItemGroup(rootContext).TaskRunner;

            int        expected = 2;
            bool       done     = false;
            Task <int> t        = new Task <int>(() => { done = true; return(expected); });

            t.Start(activationScheduler);

            int received = t.Result;

            Assert.True(t.IsCompleted, "Task should have completed");
            Assert.False(t.IsFaulted, "Task should not thrown exception: " + t.Exception);
            Assert.True(done, "Task should be done");
            Assert.Equal(expected, received);
        }
Example #7
0
        public void Sched_Task_ClosureWorkItem_SpecificScheduler()
        {
            UnitTestSchedulingContext context             = new UnitTestSchedulingContext();
            OrleansTaskScheduler      scheduler           = TestInternalHelper.InitializeSchedulerForTesting(context);
            ActivationTaskScheduler   activationScheduler = scheduler.GetWorkItemGroup(context).TaskRunner;

            var result0 = new TaskCompletionSource <bool>();
            var result1 = new TaskCompletionSource <bool>();

            Task t1 = null;

            scheduler.QueueWorkItem(new ClosureWorkItem(() =>
            {
                try
                {
                    Console.WriteLine("#0 - TaskWorkItem - SynchronizationContext.Current={0} TaskScheduler.Current={1}",
                                      SynchronizationContext.Current, TaskScheduler.Current);
                    Assert.AreEqual(activationScheduler, TaskScheduler.Current, "TaskScheduler.Current #0");

                    t1 = new Task(() =>
                    {
                        Console.WriteLine("#1 - new Task - SynchronizationContext.Current={0} TaskScheduler.Current={1}",
                                          SynchronizationContext.Current, TaskScheduler.Current);
                        Assert.AreEqual(scheduler, TaskScheduler.Current, "TaskScheduler.Current #1");
                        result1.SetResult(true);
                    });
                    t1.Start(scheduler);

                    result0.SetResult(true);
                }
                catch (Exception exc)
                {
                    result0.SetException(exc);
                }
            }), context);

            result0.Task.Wait(TimeSpan.FromSeconds(1));
            Assert.IsTrue(result0.Task.Exception == null, "Task-0 should not throw exception: " + result0.Task.Exception);
            Assert.IsTrue(result0.Task.Result, "Task-0 completed");

            Assert.IsNotNull(t1, "Task-1 started");
            result1.Task.Wait(TimeSpan.FromSeconds(1));
            Assert.IsTrue(t1.IsCompleted, "Task-1 completed");
            Assert.IsFalse(t1.IsFaulted, "Task-1 faulted: " + t1.Exception);
            Assert.IsTrue(result1.Task.Result, "Task-1 completed");
        }
        public void Async_Task_Start_ActivationTaskScheduler()
        {
            InitSchedulerLogging();
            UnitTestSchedulingContext cntx = new UnitTestSchedulingContext();
            OrleansTaskScheduler masterScheduler = TestInternalHelper.InitializeSchedulerForTesting(cntx);
            ActivationTaskScheduler activationScheduler = masterScheduler.GetWorkItemGroup(cntx).TaskRunner;

            int expected = 2;
            bool done = false;
            Task<int> t = new Task<int>(() => { done = true; return expected; });
            t.Start(activationScheduler);

            int received = t.Result;
            Assert.IsTrue(t.IsCompleted, "Task should have completed");
            Assert.IsFalse(t.IsFaulted, "Task should not thrown exception: " + t.Exception);
            Assert.IsTrue(done, "Task should be done");
            Assert.AreEqual(expected, received, "Task did not return expected value " + expected);
        }
Example #9
0
        /// <summary> Return dump of diagnostic data from this silo. </summary>
        /// <param name="all"></param>
        /// <returns>Debug data for this silo.</returns>
        public string GetDebugDump(bool all = true)
        {
            var sb = new StringBuilder();

            foreach (var systemTarget in activationDirectory.AllSystemTargets())
            {
                sb.AppendFormat("System target {0}:", ((ISystemTargetBase)systemTarget).GrainId.ToString()).AppendLine();
            }

            var enumerator = activationDirectory.GetEnumerator();

            while (enumerator.MoveNext())
            {
                Utils.SafeExecute(() =>
                {
                    var activationData = enumerator.Current.Value;
                    var workItemGroup  = scheduler.GetWorkItemGroup(activationData.SchedulingContext);
                    if (workItemGroup == null)
                    {
                        sb.AppendFormat("Activation with no work item group!! Grain {0}, activation {1}.",
                                        activationData.Grain,
                                        activationData.ActivationId);
                        sb.AppendLine();
                        return;
                    }

                    if (all || activationData.State.Equals(ActivationState.Valid))
                    {
                        sb.AppendLine(workItemGroup.DumpStatus());
                        sb.AppendLine(activationData.DumpStatus());
                    }
                });
            }
            logger.Info(ErrorCode.SiloDebugDump, sb.ToString());
            return(sb.ToString());
        }
Example #10
0
        public void ActivationSched_SimpleFifoTest()
        {
            // This is not a great test because there's a 50/50 shot that it will work even if the scheduling
            // is completely and thoroughly broken and both closures are executed "simultaneously"
            TaskScheduler scheduler = masterScheduler.GetWorkItemGroup(context).TaskRunner;

            int n = 0;
            // ReSharper disable AccessToModifiedClosure
            Task task1 = new Task(() => { Thread.Sleep(1000); n = n + 5; });
            Task task2 = new Task(() => { n = n * 3; });

            // ReSharper restore AccessToModifiedClosure

            task1.Start(scheduler);
            task2.Start(scheduler);

            // Pause to let things run
            Thread.Sleep(1500);

            // N should be 15, because the two tasks should execute in order
            Assert.True(n != 0, "Work items did not get executed");
            Assert.Equal(15, n);  // "Work items executed out of order"
        }
        public void Sched_AC_Current_TaskScheduler()
        {
            UnitTestSchedulingContext context = new UnitTestSchedulingContext();
            OrleansTaskScheduler      orleansTaskScheduler = orleansTaskScheduler = TestInternalHelper.InitializeSchedulerForTesting(context, this.performanceMetrics, this.loggerFactory);
            ActivationTaskScheduler   activationScheduler  = orleansTaskScheduler.GetWorkItemGroup(context).TaskRunner;

            // RuntimeContext.InitializeThread(masterScheduler);

            this.mainDone = false;

            var result = new TaskCompletionSource <bool>();

            Task wrapper      = null;
            Task finalPromise = null;

            orleansTaskScheduler.QueueWorkItem(new ClosureWorkItem(() =>
            {
                Log(1, "Outer ClosureWorkItem " + Task.CurrentId + " starting");
                Assert.Equal(activationScheduler, TaskScheduler.Current);   // "TaskScheduler.Current #0"

                Log(2, "Starting wrapper Task");
                wrapper = Task.Factory.StartNew(() =>
                {
                    Log(3, "Inside wrapper Task Id=" + Task.CurrentId);
                    Assert.Equal(activationScheduler, TaskScheduler.Current);   // "TaskScheduler.Current #1"

                    Log(4, "Wrapper Task " + Task.CurrentId + " creating AC chain");
                    Task promise1 = Task.Factory.StartNew(() =>
                    {
                        Log(5, "#1 Inside AC Task Id=" + Task.CurrentId);
                        Assert.Equal(activationScheduler, TaskScheduler.Current);   // "TaskScheduler.Current #1"
                        SubProcess1(1);
                    });
                    Task promise2 = promise1.ContinueWith((_) =>
                    {
                        Log(6, "#2 Inside AC Task Id=" + Task.CurrentId);
                        Assert.Equal(activationScheduler, TaskScheduler.Current);   // "TaskScheduler.Current #2"
                        SubProcess1(2);
                    });
                    finalPromise = promise2.ContinueWith((_) =>
                    {
                        Log(7, "#3 Inside final AC Task Id=" + Task.CurrentId);
                        Assert.Equal(activationScheduler, TaskScheduler.Current);   // "TaskScheduler.Current #3"
                        SubProcess1(3);
                        result.SetResult(true);
                    });
                    finalPromise.Ignore();

                    Log(8, "Wrapper Task Id=" + Task.CurrentId + " sleeping");
                    Thread.Sleep(TimeSpan.FromSeconds(1));

                    Log(9, "Wrapper Task Id=" + Task.CurrentId + " finished");
                });

                Log(10, "Outer ClosureWorkItem Task Id=" + Task.CurrentId + " sleeping");
                Thread.Sleep(TimeSpan.FromSeconds(1));
                Log(11, "Outer ClosureWorkItem Task Id=" + Task.CurrentId + " awake");

                Log(12, "Finished Outer TaskWorkItem Task Id=" + wrapper.Id);
                this.mainDone = true;
            }), context);

            Log(13, "Waiting for ClosureWorkItem to spawn wrapper Task");
            for (int i = 0; i < 5 * WaitFactor; i++)
            {
                if (wrapper != null)
                {
                    break;
                }
                Thread.Sleep(TimeSpan.FromSeconds(1).Multiply(WaitFactor));
            }
            Assert.NotNull(wrapper); // Wrapper Task was not created

            Log(14, "Waiting for wrapper Task Id=" + wrapper.Id + " to complete");
            bool finished = wrapper.Wait(TimeSpan.FromSeconds(4 * WaitFactor));

            Log(15, "Done waiting for wrapper Task Id=" + wrapper.Id + " Finished=" + finished);
            if (!finished)
            {
                throw new TimeoutException();
            }
            Assert.False(wrapper.IsFaulted, "Wrapper Task faulted: " + wrapper.Exception);
            Assert.True(wrapper.IsCompleted, "Wrapper Task should be completed");

            Log(16, "Waiting for TaskWorkItem to complete");
            for (int i = 0; i < 15 * WaitFactor; i++)
            {
                if (this.mainDone)
                {
                    break;
                }
                Thread.Sleep(1000 * WaitFactor);
            }
            Log(17, "Done waiting for TaskWorkItem to complete MainDone=" + this.mainDone);
            Assert.True(this.mainDone, "Main Task should be completed");
            Assert.NotNull(finalPromise); // AC chain not created

            Log(18, "Waiting for final AC promise to complete");
            finalPromise.Wait(TimeSpan.FromSeconds(4 * WaitFactor));
            Log(19, "Done waiting for final promise");
            Assert.False(finalPromise.IsFaulted, "Final AC faulted: " + finalPromise.Exception);
            Assert.True(finalPromise.IsCompleted, "Final AC completed");
            Assert.True(result.Task.Result, "Timeout-1");

            Assert.NotEqual(0, this.stageNum1); // "Work items did not get executed-1"
            Assert.Equal(3, this.stageNum1);    // "Work items executed out of order-1"
        }
Example #12
0
        public void Sched_Task_SchedulingContext()
        {
            UnitTestSchedulingContext context = new UnitTestSchedulingContext();

            orleansTaskScheduler = TestInternalHelper.InitializeSchedulerForTesting(context, this.performanceMetrics);
            ActivationTaskScheduler scheduler = orleansTaskScheduler.GetWorkItemGroup(context).TaskRunner;

            var  result     = new TaskCompletionSource <bool>();
            Task endOfChain = null;
            int  n          = 0;

            Task wrapper = new Task(() =>
            {
                CheckRuntimeContext(context);

                // ReSharper disable AccessToModifiedClosure
                Task task1 = Task.Factory.StartNew(() =>
                {
                    output.WriteLine("===> 1a ");
                    CheckRuntimeContext(context);
                    Thread.Sleep(1000);
                    n = n + 3;
                    output.WriteLine("===> 1b");
                    CheckRuntimeContext(context);
                });
                Task task2 = task1.ContinueWith(task =>
                {
                    output.WriteLine("===> 2");
                    CheckRuntimeContext(context);
                    n = n * 5;
                });
                Task task3 = task2.ContinueWith(task =>
                {
                    output.WriteLine("===> 3");
                    n = n / 5;
                    CheckRuntimeContext(context);
                });
                Task task4 = task3.ContinueWith(task =>
                {
                    output.WriteLine("===> 4");
                    n = n - 2;
                    result.SetResult(true);
                    CheckRuntimeContext(context);
                });
                // ReSharper restore AccessToModifiedClosure
                endOfChain = task4.ContinueWith(task =>
                {
                    output.WriteLine("Done Faulted={0}", task.IsFaulted);
                    CheckRuntimeContext(context);
                    Assert.False(task.IsFaulted, "Faulted with Exception=" + task.Exception);
                });
            });

            wrapper.Start(scheduler);
            bool ok = wrapper.Wait(TimeSpan.FromSeconds(1));

            if (!ok)
            {
                throw new TimeoutException();
            }

            Assert.False(wrapper.IsFaulted, "Wrapper Task Faulted with Exception=" + wrapper.Exception);
            Assert.True(wrapper.IsCompleted, "Wrapper Task completed");
            bool finished = result.Task.Wait(TimeSpan.FromSeconds(2));

            Assert.NotNull(endOfChain); // End of chain Task created successfully
            Assert.False(endOfChain.IsFaulted, "Task chain Faulted with Exception=" + endOfChain.Exception);
            Assert.True(finished, "Wrapper Task completed ok");
            Assert.True(n != 0, "Work items did not get executed");
            Assert.Equal(1, n);   // "Work items executed out of order"
        }
Example #13
0
        public void Sched_Task_Turn_Execution_Order()
        {
            // A unit test that checks that any turn is indeed run till completion before any other turn?
            // For example, you have a long running main turn and in the middle it spawns a lot of short CWs (on Done promise) and StartNew.
            // You test that no CW/StartNew runs until the main turn is fully done. And run in stress.

            UnitTestSchedulingContext context             = new UnitTestSchedulingContext();
            OrleansTaskScheduler      masterScheduler     = orleansTaskScheduler = TestInternalHelper.InitializeSchedulerForTesting(context, this.performanceMetrics);
            WorkItemGroup             workItemGroup       = orleansTaskScheduler.GetWorkItemGroup(context);
            ActivationTaskScheduler   activationScheduler = workItemGroup.TaskRunner;

            mainDone  = false;
            stageNum1 = stageNum2 = 0;

            var result1 = new TaskCompletionSource <bool>();
            var result2 = new TaskCompletionSource <bool>();

            Task wrapper       = null;
            Task finalTask1    = null;
            Task finalPromise2 = null;

            masterScheduler.QueueWorkItem(new ClosureWorkItem(() =>
            {
                Log(1, "Outer ClosureWorkItem " + Task.CurrentId + " starting");
                Assert.Equal(activationScheduler, TaskScheduler.Current);   // "TaskScheduler.Current #0"

                Log(2, "Starting wrapper Task");
                wrapper = Task.Factory.StartNew(() =>
                {
                    Log(3, "Inside wrapper Task Id=" + Task.CurrentId);
                    Assert.Equal(activationScheduler, TaskScheduler.Current);   // "TaskScheduler.Current #1"

                    // Execution chain #1
                    Log(4, "Wrapper Task Id=" + Task.CurrentId + " creating Task chain");
                    Task task1 = Task.Factory.StartNew(() =>
                    {
                        Log(5, "#11 Inside sub-Task Id=" + Task.CurrentId);
                        Assert.Equal(activationScheduler, TaskScheduler.Current);   // "TaskScheduler.Current #11"
                        SubProcess1(11);
                    });
                    Task task2 = task1.ContinueWith((Task task) =>
                    {
                        Log(6, "#12 Inside continuation Task Id=" + Task.CurrentId);
                        Assert.Equal(activationScheduler, TaskScheduler.Current);   // "TaskScheduler.Current #12"
                        if (task.IsFaulted)
                        {
                            throw task.Exception.Flatten();
                        }
                        SubProcess1(12);
                    });
                    Task task3 = task2.ContinueWith(task =>
                    {
                        Log(7, "#13 Inside continuation Task Id=" + Task.CurrentId);
                        Assert.Equal(activationScheduler, TaskScheduler.Current);   // "TaskScheduler.Current #13"
                        if (task.IsFaulted)
                        {
                            throw task.Exception.Flatten();
                        }
                        SubProcess1(13);
                    });
                    finalTask1 = task3.ContinueWith(task =>
                    {
                        Log(8, "#14 Inside final continuation Task Id=" + Task.CurrentId);
                        Assert.Equal(activationScheduler, TaskScheduler.Current);   // "TaskScheduler.Current #14"
                        if (task.IsFaulted)
                        {
                            throw task.Exception.Flatten();
                        }
                        SubProcess1(14);
                        result1.SetResult(true);
                    });

                    // Execution chain #2
                    Log(9, "Wrapper Task " + Task.CurrentId + " creating AC chain");
                    Task promise2 = Task.Factory.StartNew(() =>
                    {
                        Log(10, "#21 Inside sub-Task Id=" + Task.CurrentId);
                        Assert.Equal(activationScheduler, TaskScheduler.Current);   // "TaskScheduler.Current #21"
                        SubProcess2(21);
                    });
                    finalPromise2 = promise2.ContinueWith((_) =>
                    {
                        Log(11, "#22 Inside final continuation Task Id=" + Task.CurrentId);
                        Assert.Equal(activationScheduler, TaskScheduler.Current);   // "TaskScheduler.Current #22"
                        SubProcess2(22);
                        result2.SetResult(true);
                    });
                    finalPromise2.Ignore();

                    Log(12, "Wrapper Task Id=" + Task.CurrentId + " sleeping #2");
                    Thread.Sleep(TimeSpan.FromSeconds(1));

                    Log(13, "Wrapper Task Id=" + Task.CurrentId + " finished");
                });

                Log(14, "Outer ClosureWorkItem Task Id=" + Task.CurrentId + " sleeping");
                Thread.Sleep(TimeSpan.FromSeconds(1));
                Log(15, "Outer ClosureWorkItem Task Id=" + Task.CurrentId + " awake");

                Log(16, "Finished Outer ClosureWorkItem Task Id=" + wrapper.Id);
                mainDone = true;
            }), context);

            Log(17, "Waiting for ClosureWorkItem to spawn wrapper Task");
            for (int i = 0; i < 5 * waitFactor; i++)
            {
                if (wrapper != null)
                {
                    break;
                }
                Thread.Sleep(TimeSpan.FromSeconds(1).Multiply(waitFactor));
            }
            Assert.NotNull(wrapper); // Wrapper Task was not created

            Log(18, "Waiting for wrapper Task Id=" + wrapper.Id + " to complete");
            bool finished = wrapper.Wait(TimeSpan.FromSeconds(4 * waitFactor));

            Log(19, "Done waiting for wrapper Task Id=" + wrapper.Id + " Finished=" + finished);
            if (!finished)
            {
                throw new TimeoutException();
            }
            Assert.False(wrapper.IsFaulted, "Wrapper Task faulted: " + wrapper.Exception);
            Assert.True(wrapper.IsCompleted, "Wrapper Task should be completed");

            Log(20, "Waiting for TaskWorkItem to complete");
            for (int i = 0; i < 15 * waitFactor; i++)
            {
                if (mainDone)
                {
                    break;
                }
                Thread.Sleep(1000 * waitFactor);
            }
            Log(21, "Done waiting for TaskWorkItem to complete MainDone=" + mainDone);
            Assert.True(mainDone, "Main Task should be completed");
            Assert.NotNull(finalTask1);    // Task chain #1 not created
            Assert.NotNull(finalPromise2); // Task chain #2 not created

            Log(22, "Waiting for final task #1 to complete");
            bool ok = finalTask1.Wait(TimeSpan.FromSeconds(4 * waitFactor));

            Log(23, "Done waiting for final task #1 complete Ok=" + ok);
            if (!ok)
            {
                throw new TimeoutException();
            }
            Assert.False(finalTask1.IsFaulted, "Final Task faulted: " + finalTask1.Exception);
            Assert.True(finalTask1.IsCompleted, "Final Task completed");
            Assert.True(result1.Task.Result, "Timeout-1");

            Log(24, "Waiting for final promise #2 to complete");
            finalPromise2.Wait(TimeSpan.FromSeconds(4 * waitFactor));
            Log(25, "Done waiting for final promise #2");
            Assert.False(finalPromise2.IsFaulted, "Final Task faulted: " + finalPromise2.Exception);
            Assert.True(finalPromise2.IsCompleted, "Final Task completed");
            Assert.True(result2.Task.Result, "Timeout-2");

            Assert.NotEqual(0, stageNum1); // "Work items did not get executed-1"
            Assert.Equal(14, stageNum1);   // "Work items executed out of order-1"
            Assert.NotEqual(0, stageNum2); // "Work items did not get executed-2"
            Assert.Equal(22, stageNum2);   // "Work items executed out of order-2"
        }