Ejemplo n.º 1
0
    protected virtual void generateDepositAction(int depositValue)
    {
        var transaction = new TransactionRecord("Banking", _instanceCount++);

        var step = new TransactionStep(
            "Player",
            "Deposited funds",
            "Balance updated",
            depositValue
            );

        transaction.addStep(step);

        _ledger.appendTransaction(transaction);
    }
Ejemplo n.º 2
0
    protected virtual void generateWithdrawAction(int withdrawValue)
    {
        var transaction = new TransactionRecord("Banking", _instanceCount++);

        var step = new TransactionStep(
            "Player",
            "Withdrew funds",
            "Balance zeroed",
            -withdrawValue
            );

        transaction.addStep(step);

        _ledger.appendTransaction(transaction);
    }
        public void WhenRunRecoveredTransaction_ShouldProcessStepsProperly()
        {
            // Arrange
            object        transactionData = new object();
            List <string> runStepActions  = new List <string>();
            List <string> runUndoActions  = new List <string>();
            List <string> runPostActions  = new List <string>();
            Mock <ITransactionStorage <object> > storageMock   = new Mock <ITransactionStorage <object> >();
            Mock <ITransactionData <object> >    recoveredData = new Mock <ITransactionData <object> >();

            recoveredData.SetupGet(x => x.CurrentStepIndex)
            .Returns(2);
            recoveredData.SetupGet(x => x.Data)
            .Returns(transactionData);
            recoveredData.SetupGet(x => x.SessionId)
            .Returns(Guid.NewGuid());
            recoveredData.SetupGet(x => x.StartTimestamp)
            .Returns(DateTime.Now);
            storageMock.Setup(x => x.RecoverTransaction())
            .Returns(recoveredData.Object);
            ITransaction <string, object> target = new TransactionFactory().Create <string, object>(options =>
            {
                options.TransactionInfo.Name      = "test transaction";
                options.TransactionStorageCreator = context => storageMock.Object;
            });

            for (int i = 0; i < 6; ++i)
            {
                string index = i.ToString();
                TransactionStep <string, object> step = new TransactionStep <string, object>()
                {
                    Id       = index,
                    Settings = StepSettings.None
                };

                step.StepAction = (data, info) =>
                {
                    data.Should().BeSameAs(transactionData);
                    info.CurrentStepId.Should().Be(index);
                    runStepActions.Add(index);
                };

                step.UndoAction = (data, info) =>
                {
                    data.Should().BeSameAs(transactionData);
                    info.CurrentStepId.Should().Be(index);
                    runUndoActions.Add(index);
                };

                step.PostAction = (data, info) =>
                {
                    data.Should().BeSameAs(transactionData);
                    runPostActions.Add(index);
                    info.CurrentStepId.Should().Be(index);
                };

                target.Add(step);
            }
            ITransactionResult <object> result = null;

            /*
             * 0:
             * 1:
             * 2: recovered step
             * 3:
             * 4:
             * 5:
             */

            // Act
            target.Run(settings =>
            {
                settings.Data = transactionData;
                settings.Mode = RunMode.RecoverAndUndoAndRun;
                settings.TransactionResultCallback = callbackResult => result = callbackResult;
            });

            // Assert
            result.Data.Should().BeSameAs(transactionData);
            result.Errors.ShouldAllBeEquivalentTo(new Exception[0]);
            result.Recovered.Should().BeTrue();
            result.Result.Should().Be(ResultType.Success);
            runStepActions.ShouldAllBeEquivalentTo(new string[] { "0", "1", "2", "3", "4", "5" });
            runUndoActions.ShouldAllBeEquivalentTo(new string[] { "2", "1", "0" });
            runPostActions.ShouldAllBeEquivalentTo(new string[] { "0", "1", "2", "3", "4", "5" });
            storageMock.AssertStorageOperations(new AssertStorageOperationsContext <string, object>()
            {
                SessionStartedTimes = Times.Never(),
                TransactionData     = transactionData,
                Transaction         = target,
                ExpectedStepsOrder  = runStepActions,
                ExpectedUndoOrder   = runUndoActions
            });
        }
        public void WhenRunRecoveredTransactionWithCurrentStepAsFirstStepWithExecutor_ShouldProcessStepsProperly()
        {
            // Arrange
            object        transactionData                = new object();
            List <string> runStepActions                 = new List <string>();
            List <string> runUndoActions                 = new List <string>();
            List <string> runPostActions                 = new List <string>();
            List <int>    stepActionThreadId             = new List <int>();
            List <int>    undoActionThreadId             = new List <int>();
            List <int>    postActionThreadId             = new List <int>();
            int           transactionCallbackThreadId    = 0;
            int           transactionRunThreadId         = Thread.CurrentThread.ManagedThreadId;
            Dictionary <int, TestExecutor> stepExecutors = new Dictionary <int, TestExecutor>()
            {
                { 0, null },
                { 1, null },
                { 2, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 3, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 4, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 5, null },
                { 6, null }
            };
            Dictionary <int, TestExecutor> undoExecutors = new Dictionary <int, TestExecutor>()
            {
                { 0, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 1, null },
                { 2, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 3, null },
                { 4, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 5, null },
                { 6, null }
            };
            Dictionary <int, TestExecutor> postExecutors = new Dictionary <int, TestExecutor>()
            {
                { 0, null },
                { 1, null },
                { 2, null },
                { 3, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 4, null },
                { 5, null },
                { 6, null }
            };
            TestExecutor callBackExecutor = new TestExecutor()
            {
                ShouldRun = true
            };
            Mock <ITransactionStorage <object> > storageMock   = new Mock <ITransactionStorage <object> >();
            Mock <ITransactionData <object> >    recoveredData = new Mock <ITransactionData <object> >();

            recoveredData.SetupGet(x => x.CurrentStepIndex)
            .Returns(0);
            recoveredData.SetupGet(x => x.Data)
            .Returns(transactionData);
            recoveredData.SetupGet(x => x.SessionId)
            .Returns(Guid.NewGuid());
            recoveredData.SetupGet(x => x.StartTimestamp)
            .Returns(DateTime.Now);
            storageMock.Setup(x => x.RecoverTransaction())
            .Returns(recoveredData.Object);
            ITransaction <string, object> target = new TransactionFactory().Create <string, object>(options =>
            {
                options.TransactionInfo.Name      = "test transaction";
                options.TransactionStorageCreator = context => storageMock.Object;
            });

            for (int i = 0; i < 7; ++i)
            {
                string index = i.ToString();
                TransactionStep <string, object> step = new TransactionStep <string, object>()
                {
                    Id = index,
                    StepActionExecutor = stepExecutors[i],
                    UndoActionExecutor = undoExecutors[i],
                    PostActionExecutor = postExecutors[i],
                    Settings           = StepSettings.None
                };

                step.StepAction = (data, info) =>
                {
                    data.Should().BeSameAs(transactionData);
                    info.CurrentStepId.Should().Be(index);
                    runStepActions.Add(index);
                    stepActionThreadId.Add(Thread.CurrentThread.ManagedThreadId);
                };

                step.UndoAction = (data, info) =>
                {
                    data.Should().BeSameAs(transactionData);
                    info.CurrentStepId.Should().Be(index);
                    runUndoActions.Add(index);
                    undoActionThreadId.Add(Thread.CurrentThread.ManagedThreadId);
                };

                step.PostAction = (data, info) =>
                {
                    data.Should().BeSameAs(transactionData);
                    runPostActions.Add(index);
                    postActionThreadId.Add(Thread.CurrentThread.ManagedThreadId);
                    info.CurrentStepId.Should().Be(index);
                };

                target.Add(step);
            }
            ITransactionResult <object> result = null;

            /*
             * 0: recovered step, executor for other thread (undo action)
             * 1:
             * 2: executor for other thread (step action), executor for other thread (undo action)
             * 3: executor for other thread (step action), executor for other thread (post action)
             * 4: executor for other thread (step action), executor for other thread (undo action)
             * 5:
             * 6:
             */

            // Act
            using (ManualResetEvent transactionEndResetEvent = new ManualResetEvent(false))
            {
                target.Run(settings =>
                {
                    settings.Data = transactionData;
                    settings.Mode = RunMode.RecoverAndUndoAndRun;
                    settings.TransactionResultCallback = callbackResult =>
                    {
                        transactionCallbackThreadId = Thread.CurrentThread.ManagedThreadId;
                        result = callbackResult;
                        transactionEndResetEvent.Set();
                    };
                    settings.TransactionResultCallbackExecutor = callBackExecutor;
                });
                transactionEndResetEvent.WaitOne();
            }

            // Assert
            callBackExecutor.Dispose();

            foreach (TestExecutor executor in stepExecutors.Values.Concat(postExecutors.Values).Where(x => x != null))
            {
                executor.Dispose();
            }

            result.Data.Should().BeSameAs(transactionData);
            result.Errors.ShouldAllBeEquivalentTo(new Exception[0]);
            result.Recovered.Should().BeTrue();
            result.Result.Should().Be(ResultType.Success);
            callBackExecutor.Verify(Times.Once, Times.Once);

            foreach (TestExecutor executor in stepExecutors.Values.Concat(postExecutors.Values).Where(x => x != null))
            {
                executor.Verify(Times.Once, Times.Once);
            }

            runStepActions.ShouldAllBeEquivalentTo(new string[] { "0", "1", "2", "3", "4", "5", "6" });
            runUndoActions.ShouldAllBeEquivalentTo(new string[] { "0" });
            runPostActions.ShouldAllBeEquivalentTo(new string[] { "0", "1", "2", "3", "4", "5", "6" });
            stepActionThreadId.ShouldAllBeEquivalentTo(new int[]
            {
                /*step 0*/ undoExecutors[0].ThreadId,
                /*step 1*/ undoExecutors[0].ThreadId,
                /*step 2*/ stepExecutors[2].ThreadId,
                /*step 3*/ stepExecutors[3].ThreadId,
                /*step 4*/ stepExecutors[4].ThreadId,
                /*step 5*/ stepExecutors[4].ThreadId,
                /*step 6*/ stepExecutors[4].ThreadId
            });
            undoActionThreadId.ShouldAllBeEquivalentTo(new int[] { undoExecutors[0].ThreadId });
            postActionThreadId.ShouldAllBeEquivalentTo(new int[]
            {
                /*step 0*/ stepExecutors[4].ThreadId,
                /*step 1*/ stepExecutors[4].ThreadId,
                /*step 2*/ stepExecutors[4].ThreadId,
                /*step 3*/ postExecutors[3].ThreadId,
                /*step 4*/ postExecutors[3].ThreadId,
                /*step 5*/ postExecutors[3].ThreadId,
                /*step 6*/ postExecutors[3].ThreadId
            });
            transactionCallbackThreadId.Should().Be(callBackExecutor.ThreadId);
            storageMock.AssertStorageOperations(new AssertStorageOperationsContext <string, object>()
            {
                SessionStartedTimes = Times.Never(),
                TransactionData     = transactionData,
                Transaction         = target,
                ExpectedStepsOrder  = runStepActions,
                ExpectedUndoOrder   = runUndoActions
            });
        }
        public async Task WhenRunTransactionWithStepExecutorsWithSameExecutorForAllActions_ShouldRunAllStepsProperly()
        {
            // Arrange
            object        transactionData                = new object();
            List <string> runStepActions                 = new List <string>();
            List <string> runUndoActions                 = new List <string>();
            List <string> runPostActions                 = new List <string>();
            List <int>    stepActionThreadId             = new List <int>();
            List <int>    postActionThreadId             = new List <int>();
            int           transactionCallbackThreadId    = 0;
            Dictionary <int, TestExecutor> stepExecutors = new Dictionary <int, TestExecutor>()
            {
                { 0, null },
                { 1, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 2, null },
                { 3, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 4, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 5, null },
                { 6, null }
            };
            Dictionary <int, TestExecutor> postExecutors = new Dictionary <int, TestExecutor>()
            {
                { 0, null },
                { 1, null },
                { 2, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 3, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 4, null },
                { 5, null },
                { 6, null }
            };
            int transactionRunThreadId           = Thread.CurrentThread.ManagedThreadId;
            int step1StepActionThreadId          = stepExecutors[1].ThreadId;
            int step2PostActionThreadId          = postExecutors[2].ThreadId;
            int step3StepActionThreadId          = stepExecutors[3].ThreadId;
            int step3PostActionThreadId          = postExecutors[3].ThreadId;
            int step4StepActionThreadId          = stepExecutors[4].ThreadId;
            ITransaction <string, object> target = new TransactionFactory().Create <string, object>(options =>
            {
                options.TransactionInfo.Name = "test transaction";
            });

            for (int i = 0; i < 7; ++i)
            {
                string index = i.ToString();
                TransactionStep <string, object> step = new TransactionStep <string, object>()
                {
                    Id = index,
                    StepActionExecutor = stepExecutors[i] == null
                                           ? null
                                           : stepExecutors[i],
                    PostActionExecutor = postExecutors[i] == null
                                           ? null
                                           : postExecutors[i],
                    Settings = i == 1
                                ? StepSettings.SameExecutorForAllActions
                                : StepSettings.None
                };

                if (i == 3 ||
                    i == 4)
                {
                    step.AsyncStepAction = async(data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        info.CurrentStepId.Should().Be(index);
                        runStepActions.Add(index);
                        stepActionThreadId.Add(Thread.CurrentThread.ManagedThreadId);
                        await Task.CompletedTask;
                    };
                }
                else
                {
                    step.StepAction = (data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        info.CurrentStepId.Should().Be(index);
                        runStepActions.Add(index);
                        stepActionThreadId.Add(Thread.CurrentThread.ManagedThreadId);
                    };
                }

                if (i % 4 == 0)
                {
                    step.AsyncUndoAction = async(data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        info.CurrentStepId.Should().Be(index);
                        runUndoActions.Add(index);
                        await Task.CompletedTask;
                    };
                }
                else
                {
                    step.UndoAction = (data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        info.CurrentStepId.Should().Be(index);
                        runUndoActions.Add(index);
                    };
                }

                if (i == 1 ||
                    i == 2)
                {
                    step.AsyncPostAction = async(data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        runPostActions.Add(index);
                        postActionThreadId.Add(Thread.CurrentThread.ManagedThreadId);
                        info.CurrentStepId.Should().Be(index);
                        await Task.CompletedTask;
                    };
                }
                else
                {
                    step.PostAction = (data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        runPostActions.Add(index);
                        postActionThreadId.Add(Thread.CurrentThread.ManagedThreadId);
                        info.CurrentStepId.Should().Be(index);
                    };
                }

                target.Add(step);
            }
            ITransactionResult <object> transactionCallbackResult = null;

            /*
             * 0:
             * 1: executor for other thread (step action), SameExecutorForAllActions
             * 2: executor for other thread (post action)
             * 3: executor for other thread (step action), executor for other thread (post action)
             * 4: executor for other thread (step action)
             * 5:
             * 6:
             */

            // Act
            ITransactionResult <object> result = await target.Run(settings =>
            {
                settings.Data = transactionData;
                settings.Mode = RunMode.Run;
                settings.TransactionResultCallback = callbackResult =>
                {
                    transactionCallbackThreadId = Thread.CurrentThread.ManagedThreadId;
                    transactionCallbackResult   = callbackResult;
                };
            });

            // Assert
            foreach (TestExecutor executor in stepExecutors.Values.Concat(postExecutors.Values).Where(x => x != null))
            {
                executor.Dispose();
            }

            result.Should().BeSameAs(transactionCallbackResult);
            result.Data.Should().BeSameAs(transactionData);
            result.Errors.ShouldAllBeEquivalentTo(new Exception[0]);
            result.Recovered.Should().BeFalse();
            result.Result.Should().Be(ResultType.Success);
            TestExecutor sharedExecutor = stepExecutors[1];

            sharedExecutor.Verify(Times.Exactly(2), Times.Exactly(2));

            foreach (TestExecutor executor in stepExecutors.Values.Concat(postExecutors.Values).Where(x => x != null && x != sharedExecutor))
            {
                executor.Verify(Times.Once, Times.Once);
            }

            runStepActions.ShouldAllBeEquivalentTo(new string[] { "0", "1", "2", "3", "4", "5", "6" });
            runUndoActions.ShouldAllBeEquivalentTo(new string[0]);
            runPostActions.ShouldAllBeEquivalentTo(new string[] { "0", "1", "2", "3", "4", "5", "6" });
            stepActionThreadId.ShouldAllBeEquivalentTo(new int[]
            {
                /*step 0*/ transactionRunThreadId,
                /*step 1*/ step1StepActionThreadId,
                /*step 2*/ step1StepActionThreadId,
                /*step 3*/ step3StepActionThreadId,
                /*step 4*/ step4StepActionThreadId,
                /*step 5*/ step4StepActionThreadId,
                /*step 6*/ step4StepActionThreadId
            });
            postActionThreadId.ShouldAllBeEquivalentTo(new int[]
            {
                /*step 0*/ step4StepActionThreadId,
                /*step 1*/ step1StepActionThreadId,
                /*step 2*/ step2PostActionThreadId,
                /*step 3*/ step3PostActionThreadId,
                /*step 4*/ step3PostActionThreadId,
                /*step 5*/ step3PostActionThreadId,
                /*step 6*/ step3PostActionThreadId
            });
            transactionCallbackThreadId.Should().Be(step3PostActionThreadId);
        }
        public async Task WhenRunTransaction_ShouldRunAllStepsProperly()
        {
            // Arrange
            object        transactionData = new object();
            List <string> runStepActions  = new List <string>();
            List <string> runUndoActions  = new List <string>();
            List <string> runPostActions  = new List <string>();
            Mock <ITransactionStorage <object> > storageMock = new Mock <ITransactionStorage <object> >();
            ITransaction <string, object>        target      = new TransactionFactory().Create <string, object>(options =>
            {
                options.TransactionInfo.Name      = "test transaction";
                options.TransactionStorageCreator = partContext => storageMock.Object;
            });

            for (int i = 0; i < 5; ++i)
            {
                string index = i.ToString();
                TransactionStep <string, object> step = new TransactionStep <string, object>()
                {
                    Id = index
                };

                if (i % 3 == 0)
                {
                    step.AsyncStepAction = async(data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        info.CurrentStepId.Should().Be(index);
                        runStepActions.Add(index);
                        await Task.CompletedTask;
                    };
                }
                else
                {
                    step.StepAction = (data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        info.CurrentStepId.Should().Be(index);
                        runStepActions.Add(index);
                    };
                }

                if (i % 4 == 0)
                {
                    step.AsyncUndoAction = async(data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        info.CurrentStepId.Should().Be(index);
                        runUndoActions.Add(index);
                        await Task.CompletedTask;
                    };
                }
                else
                {
                    step.UndoAction = (data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        info.CurrentStepId.Should().Be(index);
                        runUndoActions.Add(index);
                    };
                }

                if (i % 2 == 0)
                {
                    step.AsyncPostAction = async(data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        runPostActions.Add(index);
                        info.CurrentStepId.Should().Be(index);
                        await Task.CompletedTask;
                    };
                }
                else
                {
                    step.PostAction = (data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        info.CurrentStepId.Should().Be(index);
                        runPostActions.Add(index);
                    };
                }

                target.Add(step);
            }
            ITransactionResult <object> transactionCallbackResult = null;

            /*
             * 0:
             * 1:
             * 2:
             * 3:
             * 4:
             */

            // Act
            ITransactionResult <object> result = await target.Run(settings =>
            {
                settings.Data = transactionData;
                settings.Mode = RunMode.Run;
                settings.TransactionResultCallback = callbackResult => transactionCallbackResult = callbackResult;
            });

            // Assert
            result.Should().BeSameAs(transactionCallbackResult);
            result.Data.Should().BeSameAs(transactionData);
            result.Errors.ShouldAllBeEquivalentTo(new Exception[0]);
            result.Recovered.Should().BeFalse();
            result.Result.Should().Be(ResultType.Success);
            runStepActions.ShouldAllBeEquivalentTo(new string[] { "0", "1", "2", "3", "4" });
            runUndoActions.ShouldAllBeEquivalentTo(new string[0]);
            runPostActions.ShouldAllBeEquivalentTo(new string[] { "0", "1", "2", "3", "4" });
            storageMock.AssertStorageOperations(new AssertStorageOperationsContext <string, object>()
            {
                TransactionData    = transactionData,
                Transaction        = target,
                ExpectedStepsOrder = runStepActions,
                ExpectedUndoOrder  = runUndoActions
            });
        }
Ejemplo n.º 7
0
        public Schedule Parse(string input)
        {
            // todo: this method handles both tokenization and parsing.  split into two.

            var stepsInput = input
                             .Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries)
                             .Where(i => !string.IsNullOrWhiteSpace(i));

            var steps        = new List <TransactionStep>();
            var transactions = new Dictionary <Object, Transaction>();
            var targets      = new List <object>();

            foreach (var stepInput in stepsInput)
            {
                var trimmedInput = stepInput.Trim();

                if (trimmedInput.Length <= 4)
                {
                    throw new FormatException("Invalid step format: " + stepInput);
                }

                var operation = trimmedInput[0];

                var openParen = trimmedInput.IndexOf('(');

                var transaction = trimmedInput.Substring(1, openParen - 1);

                if (!transactions.ContainsKey(transaction))
                {
                    transactions.Add(transaction, new Transaction
                    {
                        ID = transaction
                    });
                }

                var start = openParen + 1;

                var target = trimmedInput.Substring(start, trimmedInput.LastIndexOf(')') - start);

                if (!targets.Any(t => t.Equals(target)))
                {
                    targets.Add(target);
                }

                var step = new TransactionStep()
                {
                    Transaction = transactions[transaction],
                    Operation   = 'w'.Equals(char.ToLower(operation)) ? Operation.Write : Operation.Read,
                    Target      = targets.First(t => Equals(t, target))
                };

                transactions[transaction].Steps.Add(step);

                steps.Add(step);
            }

            return(new Schedule()
            {
                Steps = steps.ToArray()
            });
        }
Ejemplo n.º 8
0
 /// <summary>
 /// Метод, откатывающий транзакцию.
 /// </summary>
 /// <param name="step"></param>
 public abstract void Rollback(TransactionStep step);
Ejemplo n.º 9
0
 public override void Rollback(TransactionStep step)
 {
     step.Rollback();
 }
Ejemplo n.º 10
0
        public void WhenGoForwardWithComparerWithCompareFailure_ShouldFailTransaction()
        {
            // Arrange
            object        transactionData = new object();
            List <string> runStepActions  = new List <string>();
            List <string> runUndoActions  = new List <string>();
            List <string> runPostActions  = new List <string>();
            Mock <ITransactionStorage <object> > storageMock = new Mock <ITransactionStorage <object> >();
            ITransaction <string, object>        target      = new TransactionFactory().Create <string, object>(options =>
            {
                options.TransactionInfo.Name      = "test transaction";
                options.TransactionStorageCreator = partContext => storageMock.Object;
            });

            for (int i = 0; i < 5; ++i)
            {
                string index = "A" + i.ToString();
                TransactionStep <string, object> step = new TransactionStep <string, object>()
                {
                    Id = index
                };

                step.StepAction = (data, info) =>
                {
                    if (info.CurrentStepId == "A1")
                    {
                        info.GoForward("a4", StringComparer.Ordinal);
                    }

                    data.Should().BeSameAs(transactionData);
                    info.CurrentStepId.Should().Be(index);
                    runStepActions.Add(index);
                };

                step.UndoAction = (data, info) =>
                {
                    data.Should().BeSameAs(transactionData);
                    info.CurrentStepId.Should().Be(index);
                    runUndoActions.Add(index);
                };

                step.PostAction = (data, info) =>
                {
                    data.Should().BeSameAs(transactionData);
                    info.CurrentStepId.Should().Be(index);
                    runPostActions.Add(index);
                };

                target.Add(step);
            }

            /*
             * 0:
             * 1: go forward to step 4
             * 2:
             * 3:
             * 4:
             */

            // Act
            ITransactionResult <object> result = null;

            target.Run(settings =>
            {
                settings.Data = transactionData;
                settings.Mode = RunMode.Run;
                settings.TransactionResultCallback = callbackResult => result = callbackResult;
            });

            // Assert
            result.Data.Should().BeSameAs(transactionData);
            result.Errors.Count().Should().Be(1);
            result.Errors.First().Message.Contains("Could not move forward to a step with id 'a4' as the step does not exist.").Should().BeTrue();
            result.Recovered.Should().BeFalse();
            result.Result.Should().Be(ResultType.Failed);
            runStepActions.ShouldAllBeEquivalentTo(new string[] { "A0", "A1" });
            runUndoActions.ShouldAllBeEquivalentTo(new string[] { "A1", "A0" });
            runPostActions.ShouldAllBeEquivalentTo(new string[0]);
            storageMock.AssertStorageOperations(new AssertStorageOperationsContext <string, object>()
            {
                TransactionData    = transactionData,
                Transaction        = target,
                ExpectedStepsOrder = runStepActions,
                ExpectedUndoOrder  = runUndoActions
            });
        }
Ejemplo n.º 11
0
        public void WhenGoForwardWithoutComparer_ShouldMoveToStepProperly()
        {
            // Arrange
            object        transactionData = new object();
            List <string> runStepActions  = new List <string>();
            List <string> runUndoActions  = new List <string>();
            List <string> runPostActions  = new List <string>();
            Mock <ITransactionStorage <object> > storageMock = new Mock <ITransactionStorage <object> >();
            ITransaction <string, object>        target      = new TransactionFactory().Create <string, object>(options =>
            {
                options.TransactionInfo.Name      = "test transaction";
                options.TransactionStorageCreator = partContext => storageMock.Object;
            });

            for (int i = 0; i < 5; ++i)
            {
                string index = i.ToString();
                TransactionStep <string, object> step = new TransactionStep <string, object>()
                {
                    Id = index
                };

                step.StepAction = (data, info) =>
                {
                    data.Should().BeSameAs(transactionData);
                    info.CurrentStepId.Should().Be(index);

                    if (info.CurrentStepId == "1")
                    {
                        info.GoForward("4");
                    }

                    runStepActions.Add(index);
                };

                step.UndoAction = (data, info) =>
                {
                    data.Should().BeSameAs(transactionData);
                    info.CurrentStepId.Should().Be(index);
                    runUndoActions.Add(index);
                };

                step.PostAction = (data, info) =>
                {
                    data.Should().BeSameAs(transactionData);
                    info.CurrentStepId.Should().Be(index);
                    runPostActions.Add(index);
                };

                target.Add(step);
            }

            /*
             * 0:
             * 1: go forward to step 4
             * 2:
             * 3:
             * 4:
             */

            // Act
            ITransactionResult <object> result = null;

            target.Run(settings =>
            {
                settings.Data = transactionData;
                settings.Mode = RunMode.Run;
                settings.TransactionResultCallback = callbackResult => result = callbackResult;
            });

            // Assert
            result.Data.Should().BeSameAs(transactionData);
            result.Errors.ShouldAllBeEquivalentTo(new Exception[0]);
            result.Recovered.Should().BeFalse();
            result.Result.Should().Be(ResultType.Success);
            runStepActions.ShouldAllBeEquivalentTo(new string[] { "0", "1", "4" });
            runUndoActions.ShouldAllBeEquivalentTo(new string[0]);
            runPostActions.ShouldAllBeEquivalentTo(new string[] { "0", "1", "2", "3", "4" });
            storageMock.AssertStorageOperations(new AssertStorageOperationsContext <string, object>()
            {
                TransactionData    = transactionData,
                Transaction        = target,
                ExpectedStepsOrder = runStepActions,
                ExpectedUndoOrder  = runUndoActions
            });
        }
Ejemplo n.º 12
0
        public async Task WhenRunRecoveredTransactionWittCurrentStepWithUndoOnRecoverSettingAndPreviousStepsWithUndoOnRecover_ShouldUndoTheSteps()
        {
            // Arrange
            object        transactionData = new object();
            List <string> runStepActions  = new List <string>();
            List <string> runUndoActions  = new List <string>();
            List <string> runPostActions  = new List <string>();
            Mock <ITransactionStorage <object> > storageMock   = new Mock <ITransactionStorage <object> >();
            Mock <ITransactionData <object> >    recoveredData = new Mock <ITransactionData <object> >();

            recoveredData.SetupGet(x => x.CurrentStepIndex)
            .Returns(3);
            recoveredData.SetupGet(x => x.Data)
            .Returns(transactionData);
            recoveredData.SetupGet(x => x.SessionId)
            .Returns(Guid.NewGuid());
            recoveredData.SetupGet(x => x.StartTimestamp)
            .Returns(DateTime.Now);
            storageMock.Setup(x => x.RecoverTransaction())
            .Returns(Task.FromResult <ITransactionData <object> >(recoveredData.Object));
            ITransaction <string, object> target = new TransactionFactory().Create <string, object>(options =>
            {
                options.TransactionInfo.Name      = "test transaction";
                options.TransactionStorageCreator = context => storageMock.Object;
            });

            for (int i = 0; i < 6; ++i)
            {
                string index = i.ToString();
                TransactionStep <string, object> step = new TransactionStep <string, object>()
                {
                    Id       = index,
                    Settings = i == 1 || i == 2 || i == 3 ? StepSettings.UndoOnRecover : StepSettings.None
                };

                if (i % 3 == 0)
                {
                    step.AsyncStepAction = async(data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        info.CurrentStepId.Should().Be(index);
                        runStepActions.Add(index);
                        await Task.CompletedTask;
                    };
                }
                else
                {
                    step.StepAction = (data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        info.CurrentStepId.Should().Be(index);
                        runStepActions.Add(index);
                    };
                }

                if (i % 2 == 0)
                {
                    step.AsyncUndoAction = async(data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        info.CurrentStepId.Should().Be(index);
                        runUndoActions.Add(index);
                        await Task.CompletedTask;
                    };
                }
                else
                {
                    step.UndoAction = (data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        info.CurrentStepId.Should().Be(index);
                        runUndoActions.Add(index);
                    };
                }

                if (i % 3 == 0)
                {
                    step.AsyncPostAction = async(data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        runPostActions.Add(index);
                        info.CurrentStepId.Should().Be(index);
                        await Task.CompletedTask;
                    };
                }
                else
                {
                    step.PostAction = (data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        runPostActions.Add(index);
                        info.CurrentStepId.Should().Be(index);
                    };
                }

                target.Add(step);
            }
            ITransactionResult <object> transactionCallbackResult = null;

            /*
             * 0:
             * 1: undo on recover
             * 2: undo on recover
             * 3: recovered step, undo on recover
             * 4:
             * 5:
             */

            // Act
            ITransactionResult <object> result = await target.Run(settings =>
            {
                settings.Data = transactionData;
                settings.Mode = RunMode.RecoverAndContinue;
                settings.TransactionResultCallback = callbackResult => transactionCallbackResult = callbackResult;
            });

            // Assert
            result.Should().BeSameAs(transactionCallbackResult);
            result.Data.Should().BeSameAs(transactionData);
            result.Errors.ShouldAllBeEquivalentTo(new Exception[0]);
            result.Recovered.Should().BeTrue();
            result.Result.Should().Be(ResultType.Success);
            runStepActions.ShouldAllBeEquivalentTo(new string[] { "1", "2", "3", "4", "5" });
            runUndoActions.ShouldAllBeEquivalentTo(new string[] { "3", "2", "1" });
            runPostActions.ShouldAllBeEquivalentTo(new string[] { "0", "1", "2", "3", "4", "5" });
            storageMock.AssertStorageOperations(new AssertStorageOperationsContext <string, object>()
            {
                SessionStartedTimes = Times.Never(),
                TransactionData     = transactionData,
                Transaction         = target,
                ExpectedStepsOrder  = runStepActions,
                ExpectedUndoOrder   = runUndoActions
            });
        }
Ejemplo n.º 13
0
        public async Task WhenCancellTransaction_ShouldCancelProperly()
        {
            // Arrange
            object        transactionData        = new object();
            List <string> runStepActions         = new List <string>();
            List <string> runUndoActions         = new List <string>();
            List <string> runPostActions         = new List <string>();
            ITransaction <string, object> target = new TransactionFactory().Create <string, object>(options =>
            {
                options.TransactionInfo.Name = "test transaction";
            });

            for (int i = 0; i < 5; ++i)
            {
                string index = i.ToString();
                TransactionStep <string, object> step = new TransactionStep <string, object>()
                {
                    Id = index
                };

                if (i % 3 == 0)
                {
                    step.AsyncStepAction = async(data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        info.CurrentStepId.Should().Be(index);
                        runStepActions.Add(index);

                        if (index == "3")
                        {
                            info.Cancel();
                        }

                        await Task.CompletedTask;
                    };
                }
                else
                {
                    step.StepAction = (data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        info.CurrentStepId.Should().Be(index);
                        runStepActions.Add(index);
                    };
                }

                if (i % 4 == 0)
                {
                    step.AsyncUndoAction = async(data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        info.CurrentStepId.Should().Be(index);
                        runUndoActions.Add(index);
                        await Task.CompletedTask;
                    };
                }
                else
                {
                    step.UndoAction = (data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        info.CurrentStepId.Should().Be(index);
                        runUndoActions.Add(index);
                    };
                }

                if (i % 2 == 0)
                {
                    step.AsyncPostAction = async(data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        runPostActions.Add(index);
                        info.CurrentStepId.Should().Be(index);
                        await Task.CompletedTask;
                    };
                }
                else
                {
                    step.PostAction = (data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        runPostActions.Add(index);
                        info.CurrentStepId.Should().Be(index);
                    };
                }

                target.Add(step);
            }
            ITransactionResult <object> transactionCallbackResult = null;

            /*
             * 0:
             * 1:
             * 2:
             * 3: cancel
             * 4:
             */

            // Act
            ITransactionResult <object> result = await target.Run(settings =>
            {
                settings.Data = transactionData;
                settings.Mode = RunMode.Run;
                settings.TransactionResultCallback = callbackResult => transactionCallbackResult = callbackResult;
            });

            // Assert
            result.Should().BeSameAs(transactionCallbackResult);
            result.Data.Should().BeSameAs(transactionData);
            result.Errors.ShouldAllBeEquivalentTo(new Exception[0]);
            result.Recovered.Should().BeFalse();
            result.Result.Should().Be(ResultType.Cancelled);
            runStepActions.ShouldAllBeEquivalentTo(new string[] { "0", "1", "2", "3" });
            runUndoActions.ShouldAllBeEquivalentTo(new string[] { "3", "2", "1", "0" });
            runPostActions.ShouldAllBeEquivalentTo(new string[0]);
        }
Ejemplo n.º 14
0
        public void WhenRunTransactionAndErrorOccurredStepAction_ShouldRunUndoSteps()
        {
            // Arrange
            object        transactionData = new object();
            List <string> runStepActions  = new List <string>();
            List <string> runUndoActions  = new List <string>();
            List <string> runPostActions  = new List <string>();
            Exception     testException   = new Exception("test exception");
            Mock <ITransactionStorage <object> > storageMock = new Mock <ITransactionStorage <object> >();
            ITransaction <string, object>        target      = new TransactionFactory().Create <string, object>(options =>
            {
                options.TransactionInfo.Name      = "test transaction";
                options.TransactionStorageCreator = partContext => storageMock.Object;
            });

            for (int i = 0; i < 6; ++i)
            {
                string index = i.ToString();
                TransactionStep <string, object> step = new TransactionStep <string, object>()
                {
                    Id = index
                };

                step.StepAction = (data, info) =>
                {
                    data.Should().BeSameAs(transactionData);
                    info.CurrentStepId.Should().Be(index);
                    runStepActions.Add(index);

                    if (index == "3")
                    {
                        throw testException;
                    }
                };

                step.UndoAction = (data, info) =>
                {
                    data.Should().BeSameAs(transactionData);
                    info.CurrentStepId.Should().Be(index);
                    runUndoActions.Add(index);
                };

                step.PostAction = (data, info) =>
                {
                    data.Should().BeSameAs(transactionData);
                    runPostActions.Add(index);
                    info.CurrentStepId.Should().Be(index);
                };

                target.Add(step);
            }
            ITransactionResult <object> result = null;

            /*
             * 0:
             * 1:
             * 2:
             * 3: error
             * 4:
             * 5:
             */

            // Act
            target.Run(settings =>
            {
                settings.Data = transactionData;
                settings.Mode = RunMode.Run;
                settings.TransactionResultCallback = callbackResult => result = callbackResult;
            });

            // Assert
            result.Data.Should().BeSameAs(transactionData);
            result.Errors.ShouldAllBeEquivalentTo(new Exception[] { testException });
            result.Recovered.Should().BeFalse();
            result.Result.Should().Be(ResultType.Failed);
            runStepActions.ShouldAllBeEquivalentTo(new string[] { "0", "1", "2", "3" });
            runUndoActions.ShouldAllBeEquivalentTo(new string[] { "3", "2", "1", "0" });
            runPostActions.ShouldAllBeEquivalentTo(new string[0]);
            storageMock.AssertStorageOperations(new AssertStorageOperationsContext <string, object>()
            {
                TransactionData    = transactionData,
                Transaction        = target,
                ExpectedStepsOrder = runStepActions,
                ExpectedUndoOrder  = runUndoActions
            });
        }
Ejemplo n.º 15
0
 public abstract void Commit(TransactionStep step);
Ejemplo n.º 16
0
        public void WhenGoForwardWithComparerWithCompareFailureWithStepExecutors_ShouldFailTransaction()
        {
            // Arrange
            object        transactionData                = new object();
            List <string> runStepActions                 = new List <string>();
            List <string> runUndoActions                 = new List <string>();
            List <string> runPostActions                 = new List <string>();
            List <int>    stepActionThreadId             = new List <int>();
            List <int>    postActionThreadId             = new List <int>();
            int           transactionCallbackThreadId    = 0;
            Dictionary <int, TestExecutor> stepExecutors = new Dictionary <int, TestExecutor>()
            {
                { 0, null },
                { 1, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 2, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 3, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 4, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 5, null },
                { 6, null }
            };
            Dictionary <int, TestExecutor> postExecutors = new Dictionary <int, TestExecutor>()
            {
                { 0, null },
                { 1, null },
                { 2, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 3, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 4, null },
                { 5, null },
                { 6, null }
            };
            int          transactionRunThreadId = Thread.CurrentThread.ManagedThreadId;
            TestExecutor callBackExecutor       = new TestExecutor()
            {
                ShouldRun = true
            };
            ITransaction <string, object> target = new TransactionFactory().Create <string, object>(options =>
            {
                options.TransactionInfo.Name = "test transaction";
            });

            for (int i = 0; i < 7; ++i)
            {
                string index = "B" + i.ToString();
                TransactionStep <string, object> step = new TransactionStep <string, object>()
                {
                    Id = index,
                    StepActionExecutor = stepExecutors[i] == null
                                           ? null
                                           : stepExecutors[i],
                    PostActionExecutor = postExecutors[i] == null
                                           ? null
                                           : postExecutors[i]
                };

                step.StepAction = (data, info) =>
                {
                    if (info.CurrentStepId == "B2")
                    {
                        info.GoForward("b4", StringComparer.Ordinal);
                    }

                    data.Should().BeSameAs(transactionData);
                    info.CurrentStepId.Should().Be(index);
                    runStepActions.Add(index);
                    stepActionThreadId.Add(Thread.CurrentThread.ManagedThreadId);
                };

                step.UndoAction = (data, info) =>
                {
                    data.Should().BeSameAs(transactionData);
                    info.CurrentStepId.Should().Be(index);
                    runUndoActions.Add(index);
                };

                step.PostAction = (data, info) =>
                {
                    data.Should().BeSameAs(transactionData);
                    runPostActions.Add(index);
                    postActionThreadId.Add(Thread.CurrentThread.ManagedThreadId);
                    info.CurrentStepId.Should().Be(index);
                };

                target.Add(step);
            }

            /*
             * 0:
             * 1: executor for other thread (step action)
             * 2: executor for other thread (step action), executor for other thread (post action), go forward to step 4
             * 3: executor for other thread (step action), executor for other thread (post action)
             * 4: executor for other thread (step action)
             * 5:
             * 6:
             */

            // Act
            ITransactionResult <object> result = null;

            using (ManualResetEvent transactionEndResetEvent = new ManualResetEvent(false))
            {
                target.Run(settings =>
                {
                    settings.Data = transactionData;
                    settings.Mode = RunMode.Run;
                    settings.TransactionResultCallback = callbackResult =>
                    {
                        transactionCallbackThreadId = Thread.CurrentThread.ManagedThreadId;
                        result = callbackResult;
                        transactionEndResetEvent.Set();
                    };
                    settings.TransactionResultCallbackExecutor = callBackExecutor;
                });
                transactionEndResetEvent.WaitOne();
            }

            // Assert
            callBackExecutor.Dispose();

            foreach (TestExecutor executor in stepExecutors.Values.Concat(postExecutors.Values).Where(x => x != null))
            {
                executor.Dispose();
            }

            result.Data.Should().BeSameAs(transactionData);
            result.Errors.Count().Should().Be(1);
            result.Errors.First().Message.Contains("Could not move forward to a step with id 'b4' as the step does not exist.").Should().BeTrue();
            result.Recovered.Should().BeFalse();
            result.Result.Should().Be(ResultType.Failed);
            runStepActions.ShouldAllBeEquivalentTo(new string[] { "B0", "B1", "B2" });
            runUndoActions.ShouldAllBeEquivalentTo(new string[] { "B2", "B1", "B0" });
            runPostActions.ShouldAllBeEquivalentTo(new string[0]);
            stepActionThreadId.ShouldAllBeEquivalentTo(new int[]
            {
                /*step 0*/ transactionRunThreadId,
                /*step 1*/ stepExecutors[1].ThreadId,
                /*step 2*/ stepExecutors[2].ThreadId
            });
            transactionCallbackThreadId.Should().Be(callBackExecutor.ThreadId);
        }
Ejemplo n.º 17
0
        public void WhenRunTransactionWithStepExecutors_ShouldRunAllStepsProperly()
        {
            // Arrange
            object        transactionData                = new object();
            List <string> runStepActions                 = new List <string>();
            List <string> runUndoActions                 = new List <string>();
            List <string> runPostActions                 = new List <string>();
            List <int>    stepActionThreadId             = new List <int>();
            List <int>    postActionThreadId             = new List <int>();
            int           transactionCallbackThreadId    = 0;
            Dictionary <int, TestExecutor> stepExecutors = new Dictionary <int, TestExecutor>()
            {
                { 0, null },
                { 1, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 2, null },
                { 3, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 4, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 5, null },
                { 6, null }
            };
            Dictionary <int, TestExecutor> postExecutors = new Dictionary <int, TestExecutor>()
            {
                { 0, null },
                { 1, null },
                { 2, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 3, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 4, null },
                { 5, null },
                { 6, null }
            };
            int transactionRunThreadId           = Thread.CurrentThread.ManagedThreadId;
            int step1StepActionThreadId          = stepExecutors[1].ThreadId;
            int step2PostActionThreadId          = postExecutors[2].ThreadId;
            int step3StepActionThreadId          = stepExecutors[3].ThreadId;
            int step3PostActionThreadId          = postExecutors[3].ThreadId;
            int step4StepActionThreadId          = stepExecutors[4].ThreadId;
            ITransaction <string, object> target = new TransactionFactory().Create <string, object>(options =>
            {
                options.TransactionInfo.Name = "test transaction";
            });

            for (int i = 0; i < 7; ++i)
            {
                string index = i.ToString();
                TransactionStep <string, object> step = new TransactionStep <string, object>()
                {
                    Id = index,
                    StepActionExecutor = stepExecutors[i] == null
                                           ? null
                                           : stepExecutors[i],
                    PostActionExecutor = postExecutors[i] == null
                                           ? null
                                           : postExecutors[i]
                };

                step.StepAction = (data, info) =>
                {
                    data.Should().BeSameAs(transactionData);
                    info.CurrentStepId.Should().Be(index);
                    runStepActions.Add(index);
                    stepActionThreadId.Add(Thread.CurrentThread.ManagedThreadId);
                };

                step.UndoAction = (data, info) =>
                {
                    data.Should().BeSameAs(transactionData);
                    info.CurrentStepId.Should().Be(index);
                    runUndoActions.Add(index);
                };

                step.PostAction = (data, info) =>
                {
                    data.Should().BeSameAs(transactionData);
                    runPostActions.Add(index);
                    postActionThreadId.Add(Thread.CurrentThread.ManagedThreadId);
                    info.CurrentStepId.Should().Be(index);
                };

                target.Add(step);
            }
            ITransactionResult <object> result = null;

            /*
             * 0:
             * 1: executor for other thread (step action)
             * 2: executor for other thread (post action)
             * 3: executor for other thread (step action), executor for other thread (post action)
             * 4: executor for other thread (step action)
             * 5:
             * 6:
             */

            // Act
            using (ManualResetEvent transactionEndResetEvent = new ManualResetEvent(false))
            {
                target.Run(settings =>
                {
                    settings.Data = transactionData;
                    settings.Mode = RunMode.Run;
                    settings.TransactionResultCallback = callbackResult =>
                    {
                        transactionCallbackThreadId = Thread.CurrentThread.ManagedThreadId;
                        result = callbackResult;
                        transactionEndResetEvent.Set();
                    };
                });
                transactionEndResetEvent.WaitOne();
            }

            // Assert
            foreach (TestExecutor executor in stepExecutors.Values.Concat(postExecutors.Values).Where(x => x != null))
            {
                executor.Dispose();
            }

            result.Data.Should().BeSameAs(transactionData);
            result.Errors.ShouldAllBeEquivalentTo(new Exception[0]);
            result.Recovered.Should().BeFalse();
            result.Result.Should().Be(ResultType.Success);

            foreach (TestExecutor executor in stepExecutors.Values.Concat(postExecutors.Values).Where(x => x != null))
            {
                executor.Verify(Times.Once, Times.Once);
            }

            runStepActions.ShouldAllBeEquivalentTo(new string[] { "0", "1", "2", "3", "4", "5", "6" });
            runUndoActions.ShouldAllBeEquivalentTo(new string[0]);
            runPostActions.ShouldAllBeEquivalentTo(new string[] { "0", "1", "2", "3", "4", "5", "6" });
            stepActionThreadId.ShouldAllBeEquivalentTo(new int[]
            {
                /*step 0*/ transactionRunThreadId,
                /*step 1*/ step1StepActionThreadId,
                /*step 2*/ step1StepActionThreadId,
                /*step 3*/ step3StepActionThreadId,
                /*step 4*/ step4StepActionThreadId,
                /*step 5*/ step4StepActionThreadId,
                /*step 6*/ step4StepActionThreadId
            });
            postActionThreadId.ShouldAllBeEquivalentTo(new int[]
            {
                /*step 0*/ step4StepActionThreadId,
                /*step 1*/ step4StepActionThreadId,
                /*step 2*/ step2PostActionThreadId,
                /*step 3*/ step3PostActionThreadId,
                /*step 4*/ step3PostActionThreadId,
                /*step 5*/ step3PostActionThreadId,
                /*step 6*/ step3PostActionThreadId
            });
            transactionCallbackThreadId.Should().Be(step3PostActionThreadId);
        }
Ejemplo n.º 18
0
 public override void Commit(TransactionStep step)
 {
     step.Commit();
 }
Ejemplo n.º 19
0
        public async Task WhenGoForwardWithComparerWithCompareSuccessWithStepExecutors_ShouldMoveToStepProperly()
        {
            // Arrange
            object        transactionData                = new object();
            List <string> runStepActions                 = new List <string>();
            List <string> runUndoActions                 = new List <string>();
            List <string> runPostActions                 = new List <string>();
            List <int>    stepActionThreadId             = new List <int>();
            List <int>    postActionThreadId             = new List <int>();
            int           transactionCallbackThreadId    = 0;
            Dictionary <int, TestExecutor> stepExecutors = new Dictionary <int, TestExecutor>()
            {
                { 0, null },
                { 1, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 2, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 3, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 4, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 5, null },
                { 6, null }
            };
            Dictionary <int, TestExecutor> postExecutors = new Dictionary <int, TestExecutor>()
            {
                { 0, null },
                { 1, null },
                { 2, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 3, new TestExecutor()
                  {
                      ShouldRun = true
                  } },
                { 4, null },
                { 5, null },
                { 6, null }
            };
            int          transactionRunThreadId = Thread.CurrentThread.ManagedThreadId;
            TestExecutor callBackExecutor       = new TestExecutor()
            {
                ShouldRun = true
            };
            ITransaction <string, object> target = new TransactionFactory().Create <string, object>(options =>
            {
                options.TransactionInfo.Name = "test transaction";
            });

            for (int i = 0; i < 7; ++i)
            {
                string index = "B" + i.ToString();
                TransactionStep <string, object> step = new TransactionStep <string, object>()
                {
                    Id = index,
                    StepActionExecutor = stepExecutors[i] == null
                                           ? null
                                           : stepExecutors[i],
                    PostActionExecutor = postExecutors[i] == null
                                           ? null
                                           : postExecutors[i]
                };

                if (i != 2)
                {
                    step.AsyncStepAction = async(data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        info.CurrentStepId.Should().Be(index);
                        runStepActions.Add(index);
                        stepActionThreadId.Add(Thread.CurrentThread.ManagedThreadId);
                        await Task.CompletedTask;
                    };
                }
                else
                {
                    step.StepAction = (data, info) =>
                    {
                        info.GoForward("b4", StringComparer.OrdinalIgnoreCase);
                        data.Should().BeSameAs(transactionData);
                        info.CurrentStepId.Should().Be(index);
                        runStepActions.Add(index);
                        stepActionThreadId.Add(Thread.CurrentThread.ManagedThreadId);
                    };
                }

                if (i % 4 == 0)
                {
                    step.AsyncUndoAction = async(data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        info.CurrentStepId.Should().Be(index);
                        runUndoActions.Add(index);
                        await Task.CompletedTask;
                    };
                }
                else
                {
                    step.UndoAction = (data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        info.CurrentStepId.Should().Be(index);
                        runUndoActions.Add(index);
                    };
                }

                if (i == 1 ||
                    i == 2)
                {
                    step.AsyncPostAction = async(data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        runPostActions.Add(index);
                        postActionThreadId.Add(Thread.CurrentThread.ManagedThreadId);
                        info.CurrentStepId.Should().Be(index);
                        await Task.CompletedTask;
                    };
                }
                else
                {
                    step.PostAction = (data, info) =>
                    {
                        data.Should().BeSameAs(transactionData);
                        runPostActions.Add(index);
                        postActionThreadId.Add(Thread.CurrentThread.ManagedThreadId);
                        info.CurrentStepId.Should().Be(index);
                    };
                }

                target.Add(step);
            }
            ITransactionResult <object> transactionCallbackResult = null;

            /*
             * 0:
             * 1: executor for other thread (step action)
             * 2: executor for other thread (step action), executor for other thread (post action), go forward to step 4
             * 3: executor for other thread (step action), executor for other thread (post action)
             * 4: executor for other thread (step action)
             * 5:
             * 6:
             */

            // Act
            ITransactionResult <object> result = await target.Run(settings =>
            {
                settings.Data = transactionData;
                settings.Mode = RunMode.Run;
                settings.TransactionResultCallback = callbackResult =>
                {
                    transactionCallbackThreadId = Thread.CurrentThread.ManagedThreadId;
                    transactionCallbackResult   = callbackResult;
                };
                settings.TransactionResultCallbackExecutor = callBackExecutor;
            });

            // Assert
            callBackExecutor.Dispose();

            foreach (TestExecutor executor in stepExecutors.Values.Concat(postExecutors.Values).Where(x => x != null))
            {
                executor.Dispose();
            }

            result.Should().BeSameAs(transactionCallbackResult);
            result.Data.Should().BeSameAs(transactionData);
            result.Errors.ShouldAllBeEquivalentTo(new Exception[0]);
            result.Recovered.Should().BeFalse();
            result.Result.Should().Be(ResultType.Success);
            callBackExecutor.Verify(Times.Once, Times.Once);

            foreach (TestExecutor executor in stepExecutors.Values.Concat(postExecutors.Values).Where(x => x != null && x != stepExecutors[3]))
            {
                executor.Verify(Times.Once, Times.Once);
            }

            stepExecutors[3].Verify(Times.Never, Times.Never);
            runStepActions.ShouldAllBeEquivalentTo(new string[] { "B0", "B1", "B2", "B4", "B5", "B6" });
            runUndoActions.ShouldAllBeEquivalentTo(new string[0]);
            runPostActions.ShouldAllBeEquivalentTo(new string[] { "B0", "B1", "B2", "B3", "B4", "B5", "B6" });
            stepActionThreadId.ShouldAllBeEquivalentTo(new int[]
            {
                /*step 0*/ transactionRunThreadId,
                /*step 1*/ stepExecutors[1].ThreadId,
                /*step 2*/ stepExecutors[2].ThreadId,
                /*step 4*/ stepExecutors[4].ThreadId,
                /*step 5*/ stepExecutors[4].ThreadId,
                /*step 6*/ stepExecutors[4].ThreadId
            });
            postActionThreadId.ShouldAllBeEquivalentTo(new int[]
            {
                /*step 0*/ stepExecutors[4].ThreadId,
                /*step 1*/ stepExecutors[4].ThreadId,
                /*step 2*/ postExecutors[2].ThreadId,
                /*step 3*/ postExecutors[3].ThreadId,
                /*step 4*/ postExecutors[3].ThreadId,
                /*step 5*/ postExecutors[3].ThreadId,
                /*step 6*/ postExecutors[3].ThreadId
            });
            transactionCallbackThreadId.Should().Be(callBackExecutor.ThreadId);
        }