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); }
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); } }
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 }
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 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 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); } }
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 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 }
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); } }
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); } }
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); } }
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); } }
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(); }
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); } }
/// <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); }
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); } }
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 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); } }
public CastRepository(SagaContext unitOfWork) : base(unitOfWork) { }
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 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); } }
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 Manejador(SagaContext context) { _context = context; }