public override void PostSave(Saga saga, SagaContext commit, Exception error)
 {
 }
 protected UsingInitializedSagaStore()
 {
     SagaId = GuidStrategy.NewGuid();
     SagaContext = new SagaContext(typeof(FakeSaga), SagaId, new FakeEvent());
     TypeLocator.Setup(mock => mock.GetTypes(It.IsAny<Func<Type, Boolean>>())).Returns(new[] { typeof(FakeSaga) });
     SagaStore = new SqlSagaStore(Dialect, Serializer, TypeLocator.Object);
     SagaStore.Purge();
 }
            public void DoNotScheduleTimeoutIfTimeoutHasNotChanged()
            {
                var saga = new FakeSaga { Timeout = null };

                using (var context = new SagaContext(typeof(FakeSaga), GuidStrategy.NewGuid(), new FakeEvent()))
                    timeoutDispatcher.PostSave(saga, context, null);

                Assert.False(timer.Changed);
            }
 public void CurrentContextSetToNewSagaContextInstance()
 {
     var e = new FakeEvent();
     var sagaId = GuidStrategy.NewGuid();
     using (var context = new SagaContext(typeof(Saga), sagaId, e))
     {
         Assert.Same(context, SagaContext.Current);
         Assert.Equal(sagaId, SagaContext.Current.SagaId);
         Assert.Equal(typeof(Saga), SagaContext.Current.SagaType);
         Assert.Equal(e, SagaContext.Current.Event);
     }
 }
            public void CanScheduleTimeoutIfNotScheduled()
            {
                var saga = new FakeSaga();
                var e = new FakeEvent();

                using (var context = new SagaContext(typeof(Saga), GuidStrategy.NewGuid(), e))
                {
                    saga.Handle(e);

                    Assert.NotNull(saga.Timeout);
                    Assert.True(context.TimeoutChanged);
                }
            }
            public void UpdateTimerIfClearedTimeoutWasNextTimeout()
            {
                var saga = new FakeSaga {
                    CorrelationId = sagaTimeout.SagaId, Timeout = null
                };

                using (var context = new SagaContext(sagaTimeout.SagaType, sagaTimeout.SagaId, new FakeEvent()))
                {
                    context.TimeoutChanged = true;
                    timeoutDispatcher.PostSave(saga, context, null);
                }

                Assert.True(timer.Changed);
            }
            public void DoNotUpdateTimerIfClearedTimeoutWasNotNextTimeout()
            {
                var saga = new FakeSaga {
                    CorrelationId = GuidStrategy.NewGuid(), Timeout = null
                };

                using (var context = new SagaContext(sagaTimeout.SagaType, saga.CorrelationId, new FakeEvent()))
                {
                    context.TimeoutChanged = true;
                    timeoutDispatcher.PostSave(saga, context, null);
                }

                Assert.False(timer.Changed);
            }
            public void DoNotUpdateTimerIfScheduledTimeoutAfterNextCachedTimeout()
            {
                var saga = new FakeSaga {
                    CorrelationId = GuidStrategy.NewGuid(), Timeout = SystemTime.Now.AddMinutes(6)
                };

                using (var context = new SagaContext(saga.GetType(), saga.CorrelationId, new FakeEvent()))
                {
                    context.TimeoutChanged = true;
                    timeoutDispatcher.PostSave(saga, context, null);
                }

                Assert.False(timer.Changed);
            }
            public void DoNotScheduleTimeoutIfErrorNotNull()
            {
                var saga = new FakeSaga {
                    Timeout = null
                };

                using (var context = new SagaContext(typeof(FakeSaga), GuidStrategy.NewGuid(), new FakeEvent()))
                {
                    context.TimeoutChanged = true;
                    timeoutDispatcher.PostSave(saga, context, new Exception());
                }

                Assert.False(timer.Changed);
            }
Beispiel #10
0
            public void CannotScheduleTimeoutIfAlreadyScheduled()
            {
                var saga = new FakeSaga {
                    CorrelationId = GuidStrategy.NewGuid(), Timeout = SystemTime.Now
                };
                var e = new FakeEvent();

                using (var context = new SagaContext(typeof(Saga), GuidStrategy.NewGuid(), e))
                {
                    var ex = Assert.Throws <InvalidOperationException>(() => saga.Handle(e));

                    Assert.Equal(Exceptions.SagaTimeoutAlreadyScheduled.FormatWith(saga.GetType(), saga.CorrelationId), ex.Message);
                    Assert.False(context.TimeoutChanged);
                }
            }
            public void ScheduleTimeoutIfTimeoutHasValueAndSagaNotCompleted()
            {
                var saga = new FakeSaga {
                    CorrelationId = GuidStrategy.NewGuid(), Timeout = SystemTime.Now.AddMinutes(1)
                };
                var cachedItems = timeoutDispatcher.TimeoutCache.Count + 1;

                using (var context = new SagaContext(saga.GetType(), saga.CorrelationId, new FakeEvent()))
                {
                    context.TimeoutChanged = true;
                    timeoutDispatcher.PostSave(saga, context, null);
                }

                Assert.Equal(cachedItems, timeoutDispatcher.TimeoutCache.Count);
            }
            public void CollectCommandsToBePublished()
            {
                var sagaCommand1 = new SagaCommand(GuidStrategy.NewGuid(), new HeaderCollection((IEnumerable<Header>) HeaderCollection.Empty), new FakeCommand());
                var sagaCommand2 = new SagaCommand(GuidStrategy.NewGuid(), new HeaderCollection((IEnumerable<Header>)HeaderCollection.Empty), new FakeCommand());

                using (var context = new SagaContext(typeof(Saga), GuidStrategy.NewGuid(), new FakeEvent()))
                {
                    context.Publish(sagaCommand1.AggregateId, sagaCommand1.Headers, sagaCommand1.Command);
                    context.Publish(sagaCommand2.AggregateId, sagaCommand2.Headers, sagaCommand2.Command);

                    var publishedCommands = context.GetPublishedCommands().ToArray();
                    Assert.Equal(sagaCommand1.AggregateId, publishedCommands[0].AggregateId);
                    Assert.Equal(sagaCommand2.AggregateId, publishedCommands[1].AggregateId);
                }
            }
            public void ClearTimeoutIfTimeoutChangedAndHasNoValue()
            {
                var saga = new FakeSaga {
                    CorrelationId = sagaTimeout.SagaId, Timeout = null
                };
                var cachedItems = timeoutDispatcher.TimeoutCache.Count - 1;

                using (var context = new SagaContext(sagaTimeout.SagaType, sagaTimeout.SagaId, new FakeEvent()))
                {
                    context.TimeoutChanged = true;
                    timeoutDispatcher.PostSave(saga, context, null);
                }

                Assert.Equal(cachedItems, timeoutDispatcher.TimeoutCache.Count);
            }
            public void CannotDisposeContextOutOfOrder()
            {
                var context1 = new SagaContext(typeof(Saga), GuidStrategy.NewGuid(), new FakeEvent());
                var context2 = new SagaContext(typeof(Saga), GuidStrategy.NewGuid(), new FakeEvent());

                // ReSharper disable AccessToDisposedClosure
                var ex = Assert.Throws <InvalidOperationException>(() => context1.Dispose());

                // ReSharper restore AccessToDisposedClosure

                context2.Dispose();
                context1.Dispose();

                Assert.Equal(Exceptions.SagaContextInvalidThread, ex.Message);
            }
            public void CollectCommandsToBePublished()
            {
                var sagaCommand1 = new SagaCommand(GuidStrategy.NewGuid(), new HeaderCollection((IEnumerable <Header>)HeaderCollection.Empty), new FakeCommand());
                var sagaCommand2 = new SagaCommand(GuidStrategy.NewGuid(), new HeaderCollection((IEnumerable <Header>)HeaderCollection.Empty), new FakeCommand());

                using (var context = new SagaContext(typeof(Saga), GuidStrategy.NewGuid(), new FakeEvent()))
                {
                    context.Publish(sagaCommand1.AggregateId, sagaCommand1.Headers, sagaCommand1.Command);
                    context.Publish(sagaCommand2.AggregateId, sagaCommand2.Headers, sagaCommand2.Command);

                    var publishedCommands = context.GetPublishedCommands().ToArray();
                    Assert.Equal(sagaCommand1.AggregateId, publishedCommands[0].AggregateId);
                    Assert.Equal(sagaCommand2.AggregateId, publishedCommands[1].AggregateId);
                }
            }
Beispiel #16
0
            public void CanClearTimeoutIfScheduled()
            {
                var saga = new FakeSaga {
                    Timeout = SystemTime.Now
                };
                var e = new FakeEvent();

                using (var context = new SagaContext(typeof(Saga), GuidStrategy.NewGuid(), e))
                {
                    saga.Handle(e);

                    Assert.Null(saga.Timeout);
                    Assert.True(context.TimeoutChanged);
                }
            }
            public void ReturnSaveResultIfNoExceptionsThrown()
            {
                var saga               = new Mock <Saga>();
                var pipelineHook       = new Mock <PipelineHook>();
                var decoratedSagaStore = new Mock <IStoreSagas>();
                var sagaStore          = new HookableSagaStore(decoratedSagaStore.Object, new[] { pipelineHook.Object });

                // ReSharper disable AccessToDisposedClosure
                using (var context = new SagaContext(typeof(Saga), Guid.NewGuid(), new FakeEvent()))
                {
                    decoratedSagaStore.Setup(mock => mock.Save(saga.Object, context)).Returns(saga.Object);

                    Assert.Same(saga.Object, sagaStore.Save(saga.Object, context));
                }
                // ReSharper restore AccessToDisposedClosure
            }
Beispiel #18
0
            public void SagaUpdatedAfterSaveIfNotCompleted()
            {
                var saga = new FakeSaga {
                    CorrelationId = GuidStrategy.NewGuid()
                };
                var memoryCache = new MemoryCache(Guid.NewGuid().ToString());
                var sagaStore   = new Mock <IStoreSagas>();

                using (var sagaContext = new SagaContext(typeof(FakeSaga), saga.CorrelationId, new FakeEvent()))
                    using (var cachedSagaStore = new CachedSagaStore(sagaStore.Object, TimeSpan.FromMinutes(1), memoryCache))
                    {
                        cachedSagaStore.Save(saga, sagaContext);

                        Assert.Same(saga, memoryCache.Get(typeof(FakeSaga).GetFullNameWithAssembly() + '-' + saga.CorrelationId));
                    }
            }
Beispiel #19
0
            public void CanRescheduleIfTimeoutAlreadyScheduled()
            {
                var e       = new FakeEvent();
                var timeout = SystemTime.Now;
                var saga    = new FakeSaga {
                    Timeout = timeout
                };

                using (var context = new SagaContext(typeof(Saga), GuidStrategy.NewGuid(), e))
                {
                    saga.Handle(e);

                    Assert.NotEqual(timeout, saga.Timeout);
                    Assert.True(context.TimeoutChanged);
                }
            }
Beispiel #20
0
        public async Task HandleAsync(T command, ICorrelationContext context)
        {
            if (command.IsProcessable())
            {
                var sagaContext = SagaContext.FromCorrelationContext(context);
                await _sagaCoordinator.ProcessAsync(command, sagaContext);

                return;
            }

            if (await _operationsStorage.TrySetAsync(context.Id, context.UserId,
                                                     context.Name, OperationState.Pending, context.Resource, string.Empty))
            {
                await _operationPublisher.PendingAsync(context);
            }
        }
Beispiel #21
0
            public void CannotScheduleTimeoutIfTimeoutNotHandled()
            {
                var saga = new FakeSagaWithoutTimeout()
                {
                    CorrelationId = GuidStrategy.NewGuid()
                };
                var e = new FakeEvent();

                using (var context = new SagaContext(saga.GetType(), GuidStrategy.NewGuid(), e))
                {
                    var ex = Assert.Throws <InvalidOperationException>(() => saga.Handle(e));

                    Assert.Equal(Exceptions.SagaTimeoutNotHandled.FormatWith(saga.GetType()), ex.Message);
                    Assert.False(context.TimeoutChanged);
                }
            }
Beispiel #22
0
        public void CanCompleteSaga()
        {
            uow.Begin();
            persister.Save(saga);
            uow.End();

            uow.Begin();
            persister.Complete(saga);
            uow.End();

            using (var context = new SagaContext())
            {
                var sagaData = context.SagaData.FirstOrDefault(s => s.Id == saga.Id);

                Assert.IsNull(sagaData);
            }
        }
            public void InvokePreSaveHooksBeforeDecoratedSave()
            {
                var saga               = new Mock <Saga>();
                var pipelineHook       = new Mock <PipelineHook>();
                var decoratedSagaStore = new Mock <IStoreSagas>();
                var sagaStore          = new HookableSagaStore(decoratedSagaStore.Object, new[] { pipelineHook.Object });

                // ReSharper disable AccessToDisposedClosure
                using (var context = new SagaContext(typeof(Saga), Guid.NewGuid(), new FakeEvent()))
                {
                    pipelineHook.Setup(mock => mock.PreSave(saga.Object, context)).Throws(new InvalidOperationException());

                    Assert.Throws <InvalidOperationException>(() => sagaStore.Save(saga.Object, context));

                    decoratedSagaStore.Verify(mock => mock.Save(saga.Object, context), Times.Never());
                }
                // ReSharper restore AccessToDisposedClosure
            }
Beispiel #24
0
        public void CanUpdateSaga()
        {
            uow.Begin();
            persister.Save(saga);
            uow.End();

            uow.Begin();
            persister.Update(saga);
            uow.End();

            using (var context = new SagaContext())
            {
                var sagaData = context.SagaData.FirstOrDefault(s => s.Id == saga.Id);

                Assert.IsNotNull(sagaData);
                Assert.AreEqual(2, sagaData.Version);
            }
        }
Beispiel #25
0
        public void CanSaveSaga()
        {
            uow.Begin();
            persister.Save(saga);
            uow.End();

            using (var context = new SagaContext())
            {
                var sagaData = context.SagaData.FirstOrDefault(s => s.Id == saga.Id);
                context.SagaData.Remove(sagaData);
                context.SaveChanges();

                Assert.IsNotNull(sagaData);
                Assert.IsNotNull(sagaData.Data);
                Assert.IsNotNull(sagaData.UniqueProperty);
                Assert.AreEqual(1, sagaData.Version);
            }
        }
Beispiel #26
0
            public void CopyRemoteAddressHeaderFromEventContextIfNoUserAddress()
            {
                var saga        = new FakeSaga();
                var userAddress = IPAddress.Loopback.ToString();
                var e           = new FakeEvent {
                    Id = GuidStrategy.NewGuid()
                };
                var headers = new HeaderCollection(new Dictionary <String, string> {
                    { Header.RemoteAddress, userAddress }
                });

                using (new EventContext(e.Id, headers, e))
                    using (var sagaContext = new SagaContext(typeof(Saga), GuidStrategy.NewGuid(), e))
                    {
                        saga.Handle(new FakeEvent());

                        Assert.Equal(userAddress, sagaContext.GetPublishedCommands().Single().Headers.Single().Value);
                    }
            }
Beispiel #27
0
            public void CopyUserNameHeaderFromEventContext()
            {
                var saga     = new FakeSaga();
                var userName = Guid.NewGuid().ToString();
                var e        = new FakeEvent {
                    Id = GuidStrategy.NewGuid()
                };
                var headers = new HeaderCollection(new Dictionary <String, string> {
                    { Header.UserName, userName }
                });

                using (new EventContext(e.Id, headers, e))
                    using (var sagaContext = new SagaContext(typeof(Saga), GuidStrategy.NewGuid(), e))
                    {
                        saga.Handle(new FakeEvent());

                        Assert.Equal(userName, sagaContext.GetPublishedCommands().Single().Headers.Single().Value);
                    }
            }
Beispiel #28
0
            public void SagaRemovedFromCacheIfCompleted()
            {
                var saga = new FakeSaga {
                    CorrelationId = GuidStrategy.NewGuid()
                };
                var sagaStore  = new Mock <IStoreSagas>();
                var cachedSaga = default(Saga);

                using (var sagaContext = new SagaContext(typeof(FakeSaga), saga.CorrelationId, new FakeEvent()))
                    using (var cachedSagaStore = new CachedSagaStore(sagaStore.Object))
                    {
                        cachedSagaStore.Save(saga, sagaContext);

                        saga.Completed = true;

                        cachedSagaStore.Save(saga, sagaContext);

                        Assert.False(cachedSagaStore.TryGetSaga(typeof(FakeSaga), saga.CorrelationId, out cachedSaga));
                    }
            }
            public void CannotDisposeContextFromAnotherThread()
            {
                var contextDisposedEvent = new ManualResetEvent(false);
                var contextCreatedEvent  = new ManualResetEvent(false);
                var context = default(SagaContext);

                Task.Factory.StartNew(() =>
                {
                    context = new SagaContext(typeof(Saga), GuidStrategy.NewGuid(), new FakeEvent());
                    contextCreatedEvent.Set();
                    contextDisposedEvent.WaitOne();
                    context.Dispose();
                });

                contextCreatedEvent.WaitOne();

                var ex = Assert.Throws <InvalidOperationException>(() => context.Dispose());

                Assert.Equal(Exceptions.SagaContextInterleaved, ex.Message);

                contextDisposedEvent.Set();
            }
Beispiel #30
0
            public void PreferCustomHeaderOverEventContextHeaderIfDefined()
            {
                var saga           = new FakeSaga();
                var userName       = Guid.NewGuid().ToString();
                var customUserName = Guid.NewGuid().ToString();
                var e = new FakeEvent {
                    Id = GuidStrategy.NewGuid()
                };
                var headers = new HeaderCollection(new Dictionary <String, string> {
                    { Header.UserName, userName }
                });

                using (new EventContext(e.Id, headers, e))
                    using (var sagaContext = new SagaContext(typeof(Saga), GuidStrategy.NewGuid(), e))
                    {
                        saga.Handle(new FakeEvent {
                            CustomHeaders = new[] { new Header(Header.UserName, customUserName, checkReservedNames: false) }
                        });

                        Assert.Equal(customUserName, sagaContext.GetPublishedCommands().Single().Headers.Single().Value);
                    }
            }
Beispiel #31
0
        /// <summary>
        /// Save the specified <paramref name="context"/> changes for the given <paramref name="saga"/>.
        /// </summary>
        /// <param name="saga">The current saga version for which the context applies.</param>
        /// <param name="context">The saga context containing the saga changes to be applied.</param>
        public Saga Save(Saga saga, SagaContext context)
        {
            var result = sagaStore.Save(saga, context);

            if (saga.Version == 1)
            {
                statistics.IncrementInsertCount();
            }
            else
            {
                if (saga.Completed)
                {
                    statistics.IncrementDeleteCount();
                }
                else
                {
                    statistics.IncrementUpdateCount();
                }
            }

            return(result);
        }
Beispiel #32
0
            public void SagaRemovedFromCacheIfConcurrencyExceptionThrown()
            {
                var saga = new FakeSaga {
                    CorrelationId = GuidStrategy.NewGuid()
                };
                var sagaStore  = new Mock <IStoreSagas>();
                var cachedSaga = default(Saga);
                var save       = 0;

                using (var sagaContext = new SagaContext(typeof(FakeSaga), saga.CorrelationId, new FakeEvent()))
                    using (var cachedSagaStore = new CachedSagaStore(sagaStore.Object))
                    {
                        sagaStore.Setup(mock => mock.Save(It.IsAny <Saga>(), sagaContext)).Callback(() => { if (save++ == 1)
                                                                                                            {
                                                                                                                throw new ConcurrencyException();
                                                                                                            }
                                                                                                    });
                        cachedSagaStore.Save(saga, sagaContext);

                        Assert.True(cachedSagaStore.TryGetSaga(typeof(FakeSaga), saga.CorrelationId, out cachedSaga));
                        Assert.Throws <ConcurrencyException>(() => cachedSagaStore.Save(saga, sagaContext));
                        Assert.False(cachedSagaStore.TryGetSaga(typeof(FakeSaga), saga.CorrelationId, out cachedSaga));
                    }
            }
            public void CannotDisposeContextFromAnotherThread()
            {
                var contextDisposedEvent = new ManualResetEvent(false);
                var contextCreatedEvent = new ManualResetEvent(false);
                var context = default(SagaContext);

                Task.Factory.StartNew(() =>
                    {
                        context = new SagaContext(typeof(Saga), GuidStrategy.NewGuid(), new FakeEvent());
                        contextCreatedEvent.Set();
                        contextDisposedEvent.WaitOne();
                        context.Dispose();
                    });

                contextCreatedEvent.WaitOne();

                var ex = Assert.Throws<InvalidOperationException>(() => context.Dispose());

                Assert.Equal(Exceptions.SagaContextInterleaved, ex.Message);

                contextDisposedEvent.Set();
            }
 public override void PreSave(Saga saga, SagaContext context)
 {
 }
            public void ReturnSaveResultIfNoExceptionsThrown()
            {
                var saga = new Mock<Saga>();
                var pipelineHook = new Mock<PipelineHook>();
                var decoratedSagaStore = new Mock<IStoreSagas>();
                var sagaStore = new HookableSagaStore(decoratedSagaStore.Object, new[] { pipelineHook.Object });

                // ReSharper disable AccessToDisposedClosure
                using (var context = new SagaContext(typeof(Saga), Guid.NewGuid(), new FakeEvent()))
                {
                    decoratedSagaStore.Setup(mock => mock.Save(saga.Object, context)).Returns(saga.Object);

                    Assert.Same(saga.Object, sagaStore.Save(saga.Object, context));
                }
                // ReSharper restore AccessToDisposedClosure
            }
            public void InvokePostSaveHooksIfDecoratedSaveThrowsException()
            {
                var saga = new Mock<Saga>();
                var pipelineHook = new Mock<PipelineHook>();
                var error = new InvalidOperationException();
                var decoratedSagaStore = new Mock<IStoreSagas>();
                var sagaStore = new HookableSagaStore(decoratedSagaStore.Object, new[] { pipelineHook.Object });

                // ReSharper disable AccessToDisposedClosure
                using (var context = new SagaContext(typeof(Saga), Guid.NewGuid(), new FakeEvent()))
                {
                    decoratedSagaStore.Setup(mock => mock.Save(saga.Object, context)).Throws(error);

                    Assert.Throws<InvalidOperationException>(() => sagaStore.Save(saga.Object, context));

                    pipelineHook.Verify(mock => mock.PostSave(saga.Object, context, error), Times.Once());
                }
                // ReSharper restore AccessToDisposedClosure
            }
            public void CopyUserNameHeaderFromEventContext()
            {
                var saga = new FakeSaga();
                var userName = Guid.NewGuid().ToString();
                var e = new FakeEvent { Id = GuidStrategy.NewGuid() };
                var headers = new HeaderCollection(new Dictionary<String, string> { { Header.UserName, userName } });

                using (new EventContext(e.Id, headers, e))
                using (var sagaContext = new SagaContext(typeof(Saga), GuidStrategy.NewGuid(), e))
                {
                    saga.Handle(new FakeEvent());

                    Assert.Equal(userName, sagaContext.GetPublishedCommands().Single().Headers.Single().Value);
                }
            }
Beispiel #38
0
        public async Task CalculatePriceForEurope()
        {
            // Arrange / Given
            var orchContext = new SagaContext
            {
                Continent = "Europe"
            };
            var context = new Mock <IDurableOrchestrationContext>();

            // mock the get input
            context.Setup(m =>
                          m.GetInput <SagaContext>()).Returns(orchContext);

            //set-up mocks for activities
            context.Setup(m =>
                          m.CallActivityAsync <bool>("IsContinentSupported", It.IsAny <object>()))
            .ReturnsAsync(true);

            // set-up mocks for activity
            context.Setup(m
                          => m.CallActivityAsync <string>("GetSupplierOrchestratorForContinent", It.IsAny <object>()))
            .ReturnsAsync("CourierB");


            // set-up mocks for suborchstrators
            context.Setup(m =>
                          m.CallSubOrchestratorAsync <decimal>("CourierAOrchestrator", It.IsAny <string>(), It.IsAny <object>()))
            .ReturnsAsync(100);

            context.Setup(m =>
                          m.CallSubOrchestratorAsync <decimal>("CourierBOrchestrator", It.IsAny <string>(), It.IsAny <object>()))
            .ReturnsAsync(120);

            // mock the publish activity
            // at the time of writing, there is no way of mocking CallActivityAsync so we need to use the generic version
            context.Setup(m =>
                          m.CallActivityAsync <object>("PublishCalculatedPriceActivity", It.IsAny <object>())
                          );


            // ACT / When
            var price = await SagaToTestOrchestrator.RunOrchestrator(context.Object);

            // Assert / Then

            context.Verify(
                m => m.CallActivityAsync <bool>(
                    "IsContinentSupported",
                    It.IsAny <object>()),
                Times.Once);

            context.Verify(
                m => m.CallActivityAsync <string>(
                    "GetSupplierOrchestratorForContinent", It.IsAny <object>()),
                Times.Once
                );

            context.Verify(m =>
                           m.CallSubOrchestratorAsync <decimal>("CourierAOrchestrator", It.IsAny <string>(), It.IsAny <object>()),
                           Times.Never);

            context.Verify(m =>
                           m.CallSubOrchestratorAsync <decimal>("CourierBOrchestrator", It.IsAny <string>(), It.IsAny <object>()),
                           Times.Once);

            context.Verify(m =>
                           m.CallActivityAsync <object>("PublishCalculatedPriceActivity", It.IsAny <object>()),
                           Times.Once
                           );
        }
 public void CanCallDisposeMoreThanOnce()
 {
     using (var context = new SagaContext(typeof(Saga), GuidStrategy.NewGuid(), new FakeEvent()))
     {
         context.Dispose();
         context.Dispose();
     }
 }
            public void CannotScheduleTimeoutIfAlreadyScheduled()
            {
                var saga = new FakeSaga { CorrelationId = GuidStrategy.NewGuid(), Timeout = SystemTime.Now };
                var e = new FakeEvent();

                using (var context = new SagaContext(typeof(Saga), GuidStrategy.NewGuid(), e))
                {
                    var ex = Assert.Throws<InvalidOperationException>(() => saga.Handle(e));

                    Assert.Equal(Exceptions.SagaTimeoutAlreadyScheduled.FormatWith(saga.GetType(), saga.CorrelationId), ex.Message);
                    Assert.False(context.TimeoutChanged);
                }
            }
            public void CanClearTimeoutIfScheduled()
            {
                var saga = new FakeSaga { Timeout = SystemTime.Now };
                var e = new FakeEvent();

                using (var context = new SagaContext(typeof(Saga), GuidStrategy.NewGuid(), e))
                {
                    saga.Handle(e);

                    Assert.Null(saga.Timeout);
                    Assert.True(context.TimeoutChanged);
                }
            }
            public void CanRescheduleIfTimeoutAlreadyScheduled()
            {
                var e = new FakeEvent();
                var timeout = SystemTime.Now;
                var saga = new FakeSaga { Timeout = timeout };

                using (var context = new SagaContext(typeof(Saga), GuidStrategy.NewGuid(), e))
                {
                    saga.Handle(e);

                    Assert.NotEqual(timeout, saga.Timeout);
                    Assert.True(context.TimeoutChanged);
                }
            }
            public void DoNotScheduleTimeoutIfSagaNull()
            {
                using (var context = new SagaContext(typeof(FakeSaga), GuidStrategy.NewGuid(), new FakeEvent()))
                {
                    context.TimeoutChanged = true;
                    timeoutDispatcher.PostSave(null, context, null);
                }

                Assert.False(timer.Changed);
            }
            public void CopyRemoteAddressHeaderFromEventContextIfNoUserAddress()
            {
                var saga = new FakeSaga();
                var userAddress = IPAddress.Loopback.ToString();
                var e = new FakeEvent { Id = GuidStrategy.NewGuid() };
                var headers = new HeaderCollection(new Dictionary<String, string> { { Header.RemoteAddress, userAddress } });

                using (new EventContext(e.Id, headers, e))
                using (var sagaContext = new SagaContext(typeof(Saga), GuidStrategy.NewGuid(), e))
                {
                    saga.Handle(new FakeEvent());

                    Assert.Equal(userAddress, sagaContext.GetPublishedCommands().Single().Headers.Single().Value);
                }
            }
Beispiel #45
0
 public CastRepository(SagaContext unitOfWork)
     : base(unitOfWork)
 {
 }
            public void ScheduleTimeoutIfTimeoutHasValueAndSagaNotCompleted()
            {
                var saga = new FakeSaga { CorrelationId = GuidStrategy.NewGuid(), Timeout = SystemTime.Now.AddMinutes(1) };
                var cachedItems = timeoutDispatcher.TimeoutCache.Count + 1;

                using (var context = new SagaContext(saga.GetType(), saga.CorrelationId, new FakeEvent()))
                {
                    context.TimeoutChanged = true;
                    timeoutDispatcher.PostSave(saga, context, null);
                }

                Assert.Equal(cachedItems, timeoutDispatcher.TimeoutCache.Count);
            }
            public void ReturnFriendlyDescription()
            {
                var sagaType = typeof(Saga);
                var sagaId = GuidStrategy.NewGuid();

                using (var context = new SagaContext(sagaType, sagaId, new FakeEvent()))
                    Assert.Equal($"{sagaType} - {sagaId}", context.ToString());
            }
            public void DoNotScheduleTimeoutIfErrorNotNull()
            {
                var saga = new FakeSaga { Timeout = null };

                using (var context = new SagaContext(typeof(FakeSaga), GuidStrategy.NewGuid(), new FakeEvent()))
                {
                    context.TimeoutChanged = true;
                    timeoutDispatcher.PostSave(saga, context, new Exception());
                }

                Assert.False(timer.Changed);
            }
            public void CannotDisposeContextOutOfOrder()
            {
                var context1 = new SagaContext(typeof(Saga), GuidStrategy.NewGuid(), new FakeEvent());
                var context2 = new SagaContext(typeof(Saga), GuidStrategy.NewGuid(), new FakeEvent());

                // ReSharper disable AccessToDisposedClosure
                var ex = Assert.Throws<InvalidOperationException>(() => context1.Dispose());
                // ReSharper restore AccessToDisposedClosure

                context2.Dispose();
                context1.Dispose();

                Assert.Equal(Exceptions.SagaContextInvalidThread, ex.Message);
            }
            public void TimeoutRepresentedAsUtcDateTime()
            {
                var saga = new FakeSaga();
                var e = new FakeEvent();

                using (var context = new SagaContext(typeof(Saga), GuidStrategy.NewGuid(), e))
                {
                    saga.Handle(e);

                    Assert.Equal(DateTimeKind.Utc, saga.Timeout.GetValueOrDefault().Kind);
                    Assert.True(context.TimeoutChanged);
                }
            }
        /// <summary>
        /// Save the specified <paramref name="context"/> changes for the given <paramref name="saga"/>.
        /// </summary>
        /// <param name="saga">The current saga version for which the context applies.</param>
        /// <param name="context">The saga context containing the saga changes to be applied.</param>
        public Saga Save(Saga saga, SagaContext context)
        {
            Verify.NotNull(saga, nameof(saga));

            if (saga.Version == 0 && saga.Completed)
                return saga;

            if (saga.Completed)
            {
                if (saga.Version > 0)
                    DeleteSaga(saga);
            }
            else
            {
                if (saga.Version == 0)
                    InsertSaga(saga);
                else
                    UpdateSaga(saga);
            }

            return saga;
        }
            public void CannotScheduleTimeoutIfTimeoutNotHandled()
            {
                var saga = new FakeSagaWithoutTimeout() { CorrelationId = GuidStrategy.NewGuid() };
                var e = new FakeEvent();

                using (var context = new SagaContext(saga.GetType(), GuidStrategy.NewGuid(), e))
                {
                    var ex = Assert.Throws<InvalidOperationException>(() => saga.Handle(e));

                    Assert.Equal(Exceptions.SagaTimeoutNotHandled.FormatWith(saga.GetType()), ex.Message);
                    Assert.False(context.TimeoutChanged);
                }
            }
            public void SagaUpdatedAfterSaveIfNotCompleted()
            {
                var saga = new FakeSaga { CorrelationId = GuidStrategy.NewGuid() };
                var memoryCache = new MemoryCache(Guid.NewGuid().ToString());
                var sagaStore = new Mock<IStoreSagas>();

                using (var sagaContext = new SagaContext(typeof(FakeSaga), saga.CorrelationId, new FakeEvent()))
                using (var cachedSagaStore = new CachedSagaStore(sagaStore.Object, TimeSpan.FromMinutes(1), memoryCache))
                {
                    cachedSagaStore.Save(saga, sagaContext);

                    Assert.Same(saga, memoryCache.Get(typeof(FakeSaga).GetFullNameWithAssembly() + '-' + saga.CorrelationId));
                }
            }
            public void PreferCustomHeaderOverEventContextHeaderIfDefined()
            {
                var saga = new FakeSaga();
                var userName = Guid.NewGuid().ToString();
                var customUserName = Guid.NewGuid().ToString();
                var e = new FakeEvent { Id = GuidStrategy.NewGuid() };
                var headers = new HeaderCollection(new Dictionary<String, string> { { Header.UserName, userName } });

                using (new EventContext(e.Id, headers, e))
                using (var sagaContext = new SagaContext(typeof(Saga), GuidStrategy.NewGuid(), e))
                {
                    saga.Handle(new FakeEvent { CustomHeaders = new[] { new Header(Header.UserName, customUserName, checkReservedNames: false) } });

                    Assert.Equal(customUserName, sagaContext.GetPublishedCommands().Single().Headers.Single().Value);
                }
            }
Beispiel #55
0
 public PersonRepository(SagaContext unitOfWork)
     : base(unitOfWork)
 {
 }
            public void SagaRemovedFromCacheIfCompleted()
            {
                var saga = new FakeSaga { CorrelationId = GuidStrategy.NewGuid() };
                var sagaStore = new Mock<IStoreSagas>();
                var cachedSaga = default(Saga);

                using (var sagaContext = new SagaContext(typeof(FakeSaga), saga.CorrelationId, new FakeEvent()))
                using (var cachedSagaStore = new CachedSagaStore(sagaStore.Object))
                {
                    cachedSagaStore.Save(saga, sagaContext);

                    saga.Completed = true;

                    cachedSagaStore.Save(saga, sagaContext);

                    Assert.False(cachedSagaStore.TryGetSaga(typeof(FakeSaga), saga.CorrelationId, out cachedSaga));
                }
            }
            public void SagaRemovedFromCacheIfConcurrencyExceptionThrown()
            {
                var saga = new FakeSaga { CorrelationId = GuidStrategy.NewGuid() };
                var sagaStore = new Mock<IStoreSagas>();
                var cachedSaga = default(Saga);
                var save = 0;

                using (var sagaContext = new SagaContext(typeof(FakeSaga), saga.CorrelationId, new FakeEvent()))
                using (var cachedSagaStore = new CachedSagaStore(sagaStore.Object))
                {
                    sagaStore.Setup(mock => mock.Save(It.IsAny<Saga>(), sagaContext)).Callback(() => { if (save++ == 1) { throw new ConcurrencyException(); } });
                    cachedSagaStore.Save(saga, sagaContext);

                    Assert.True(cachedSagaStore.TryGetSaga(typeof(FakeSaga), saga.CorrelationId, out cachedSaga));
                    Assert.Throws<ConcurrencyException>(() => cachedSagaStore.Save(saga, sagaContext));
                    Assert.False(cachedSagaStore.TryGetSaga(typeof(FakeSaga), saga.CorrelationId, out cachedSaga));
                }
            }
            public void ClearTimeoutIfTimeoutChangedAndHasNoValue()
            {
                var saga = new FakeSaga { CorrelationId = sagaTimeout.SagaId, Timeout = null };
                var cachedItems = timeoutDispatcher.TimeoutCache.Count - 1;

                using (var context = new SagaContext(sagaTimeout.SagaType, sagaTimeout.SagaId, new FakeEvent()))
                {
                    context.TimeoutChanged = true;
                    timeoutDispatcher.PostSave(saga, context, null);
                }

                Assert.Equal(cachedItems, timeoutDispatcher.TimeoutCache.Count);
            }
Beispiel #59
0
 public Manejador(SagaContext context)
 {
     _context = context;
 }
            public void DoNotUpdateTimerIfScheduledTimeoutAfterNextCachedTimeout()
            {
                var saga = new FakeSaga { CorrelationId = GuidStrategy.NewGuid(), Timeout = SystemTime.Now.AddMinutes(6) };

                using (var context = new SagaContext(saga.GetType(), saga.CorrelationId, new FakeEvent()))
                {
                    context.TimeoutChanged = true;
                    timeoutDispatcher.PostSave(saga, context, null);
                }

                Assert.False(timer.Changed);
            }