public void SetAsProcessed_should_throw_ArgumentException_if_message_correlation_id_invalid() { var sut = new DummySagaState(Guid.NewGuid()); var message = StartDummySaga.New(); Assert.Throws <ArgumentException>(() => sut.SetAsProcessed(message)); }
public async Task RunAsync_should_throw_if_saga_cannot_handle_message() { var message = UnhandledMessage.New(); var messageContext = NSubstitute.Substitute.For <IMessageContext <UnhandledMessage> >(); messageContext.Message.Returns(message); var sagaStateService = NSubstitute.Substitute.For <ISagaStateService <DummySaga, DummySagaState> >(); var state = new DummySagaState(message.CorrelationId); sagaStateService.GetAsync(messageContext, Arg.Any <CancellationToken>()) .Returns((state, Guid.NewGuid())); var saga = NSubstitute.Substitute.ForPartsOf <DummySaga>(state); var sagaFactory = NSubstitute.Substitute.For <ISagaFactory <DummySaga, DummySagaState> >(); sagaFactory.Create(state) .Returns(saga); var logger = NSubstitute.Substitute.For <ILogger <SagaRunner <DummySaga, DummySagaState> > >(); var transactionManager = NSubstitute.Substitute.For <ITransactionManager>(); var policyFactory = NSubstitute.Substitute.For <ISagaPolicyFactory <DummySaga> >(); var sut = new SagaRunner <DummySaga, DummySagaState>(sagaFactory, sagaStateService, transactionManager, policyFactory, logger); await Assert.ThrowsAsync <ConsumerNotFoundException>(() => sut.RunAsync(messageContext, CancellationToken.None)); }
public void IsCompleted_should_return_true_after_state_is_marked_as_completed() { var state = new DummySagaState(Guid.NewGuid()); state.MarkAsCompleted(); state.IsCompleted().Should().BeTrue(); }
public async Task GetAsync_should_return_state_from_factory_if_message_can_start_saga() { var expectedState = new DummySagaState(Guid.NewGuid()); var message = StartDummySaga.New(); var messageContext = NSubstitute.Substitute.For <IMessageContext <StartDummySaga> >(); messageContext.Message.Returns(message); var sagaStateFactory = NSubstitute.Substitute.For <ISagaStateFactory <DummySagaState> >(); sagaStateFactory.Create(message) .Returns(expectedState); var sagaStateRepo = NSubstitute.Substitute.For <ISagaStateRepository>(); sagaStateRepo.LockAsync(message.CorrelationId, expectedState, Arg.Any <CancellationToken>()) .Returns(Task.FromResult((expectedState, Guid.NewGuid()))); var sut = new SagaStateService <DummySaga, DummySagaState>(sagaStateFactory, sagaStateRepo); var result = await sut.GetAsync(messageContext, CancellationToken.None); result.state.Should().Be(expectedState); }
public async Task RunAsync_should_use_transaction() { var message = new StartDummySaga(Guid.NewGuid(), Guid.NewGuid()); var messageContext = NSubstitute.Substitute.For <IMessageContext <StartDummySaga> >(); messageContext.Message.Returns(message); var sagaStateService = NSubstitute.Substitute.For <ISagaStateService <DummySaga, DummySagaState> >(); var state = new DummySagaState(message.CorrelationId); sagaStateService.GetAsync(messageContext, Arg.Any <CancellationToken>()) .Returns((state, Guid.NewGuid())); var saga = NSubstitute.Substitute.ForPartsOf <DummySaga>(state); saga.When(s => s.HandleAsync(Arg.Any <IMessageContext <StartDummySaga> >(), Arg.Any <CancellationToken>())) .DoNotCallBase(); var sagaFactory = NSubstitute.Substitute.For <ISagaFactory <DummySaga, DummySagaState> >(); sagaFactory.Create(state) .Returns(saga); var logger = NSubstitute.Substitute.For <ILogger <SagaRunner <DummySaga, DummySagaState> > >(); var transaction = NSubstitute.Substitute.For <ITransaction>(); var transactionManager = NSubstitute.Substitute.For <ITransactionManager>(); transactionManager.StartTransactionAsync(default)
public void SetState_should_set_state() { var state = new DummySagaState(Guid.NewGuid()); var sut = new DummySaga(state); sut.State.Should().Be(state); }
public void Create_should_create_valid_instance() { var state = new DummySagaState(Guid.NewGuid()); var expectedSaga = new DummySaga(); var sp = NSubstitute.Substitute.For <IServiceProvider>(); sp.GetService(typeof(DummySaga)) .Returns(expectedSaga); var bus = NSubstitute.Substitute.For <IMessageBus>(); sp.GetService(typeof(IMessageBus)) .Returns(bus); var scope = NSubstitute.Substitute.For <IServiceScope>(); scope.ServiceProvider.Returns(sp); var factory = NSubstitute.Substitute.For <IServiceScopeFactory>(); factory.CreateScope().Returns(scope); sp.GetService(typeof(IServiceScopeFactory)) .Returns(factory); var sut = new DefaultSagaFactory <DummySaga, DummySagaState>(sp); var saga = sut.Create(state); saga.Should().NotBeNull(); saga.State.Should().Be(state); }
public void CheckWasProcessed_should_return_true_if_message_processed() { var sut = new DummySagaState(Guid.NewGuid()); var message = new StartDummySaga(Guid.NewGuid(), sut.Id); sut.SetAsProcessed(message); sut.CheckWasProcessed(message).Should().BeTrue(); }
public async Task RunAsync_should_retry_if_saga_state_locked() { var message = StartDummySaga.New(); var messageContext = NSubstitute.Substitute.For <IMessageContext <StartDummySaga> >(); messageContext.Message.Returns(message); var sagaStateService = NSubstitute.Substitute.For <ISagaStateService <DummySaga, DummySagaState> >(); var state = new DummySagaState(message.CorrelationId); var firstCall = true; sagaStateService.When(s => s.GetAsync(messageContext, Arg.Any <CancellationToken>())) .Do(_ => { if (firstCall) { firstCall = false; throw new LockException("lorem"); } }); sagaStateService.GetAsync(messageContext, Arg.Any <CancellationToken>()) .Returns((state, Guid.NewGuid())); var saga = NSubstitute.Substitute.ForPartsOf <DummySaga>(); saga.SetBus(NSubstitute.Substitute.For <IMessageBus>()); saga.When(s => s.HandleAsync(Arg.Any <IMessageContext <StartDummySaga> >(), Arg.Any <CancellationToken>())) .DoNotCallBase(); var sagaFactory = NSubstitute.Substitute.For <ISagaFactory <DummySaga, DummySagaState> >(); sagaFactory.Create(state) .Returns(saga); var logger = NSubstitute.Substitute.For <ILogger <SagaRunner <DummySaga, DummySagaState> > >(); var uow = NSubstitute.Substitute.For <IUnitOfWork>(); var sut = new SagaRunner <DummySaga, DummySagaState>(sagaFactory, sagaStateService, uow, logger); await sut.RunAsync(messageContext, CancellationToken.None); await saga.Received(1) .HandleAsync(messageContext, Arg.Any <CancellationToken>()); await sagaStateService.Received(2) .GetAsync(messageContext, Arg.Any <CancellationToken>()); }
public async Task SaveAsync_should_unlock_state() { var sagaStateFactory = NSubstitute.Substitute.For <ISagaStateFactory <DummySagaState> >(); var sagaStateRepo = NSubstitute.Substitute.For <ISagaStateRepository>(); var sut = new SagaStateService <DummySaga, DummySagaState>(sagaStateFactory, sagaStateRepo); var state = new DummySagaState(Guid.NewGuid()); var lockId = Guid.NewGuid(); await sut.SaveAsync(state, lockId, null, CancellationToken.None); await sagaStateRepo.Received(1) .ReleaseLockAsync(state, lockId, null, CancellationToken.None); }
public async Task RunAsync_should_execute_saga_handler_with_policy_when_available() { var message = new StartDummySaga(Guid.NewGuid(), Guid.NewGuid()); var messageContext = NSubstitute.Substitute.For <IMessageContext <StartDummySaga> >(); messageContext.Message.Returns(message); var sagaStateService = NSubstitute.Substitute.For <ISagaStateService <DummySaga, DummySagaState> >(); var state = new DummySagaState(message.CorrelationId); sagaStateService.GetAsync(messageContext, Arg.Any <CancellationToken>()) .Returns((state, Guid.NewGuid())); var saga = NSubstitute.Substitute.ForPartsOf <DummySaga>(); saga.SetBus(NSubstitute.Substitute.For <IMessageBus>()); saga.When(s => s.HandleAsync(Arg.Any <IMessageContext <StartDummySaga> >(), Arg.Any <CancellationToken>())) .DoNotCallBase(); var sagaFactory = NSubstitute.Substitute.For <ISagaFactory <DummySaga, DummySagaState> >(); sagaFactory.Create(state) .Returns(saga); var logger = NSubstitute.Substitute.For <ILogger <SagaRunner <DummySaga, DummySagaState> > >(); var transactionManager = NSubstitute.Substitute.For <ITransactionManager>(); var policyFactory = NSubstitute.Substitute.For <ISagaPolicyFactory <DummySaga> >(); var policy = new FakePolicy(); policyFactory.Create <StartDummySaga>().ReturnsForAnyArgs(policy); var sut = new SagaRunner <DummySaga, DummySagaState>(sagaFactory, sagaStateService, transactionManager, policyFactory, logger); await sut.RunAsync(messageContext, CancellationToken.None); await saga.Received(1) .HandleAsync(messageContext, Arg.Any <CancellationToken>()); }
public async Task RunAsync_should_not_execute_handler_if_saga_is_marked_as_completed() { var message = new StartDummySaga(Guid.NewGuid(), Guid.NewGuid()); var messageContext = NSubstitute.Substitute.For <IMessageContext <StartDummySaga> >(); messageContext.Message.Returns(message); var state = new DummySagaState(message.CorrelationId); state.MarkAsCompleted(); var saga = NSubstitute.Substitute.ForPartsOf <DummySaga>(state); saga.When(s => s.HandleAsync(Arg.Any <IMessageContext <StartDummySaga> >(), Arg.Any <CancellationToken>())) .DoNotCallBase(); var sagaFactory = NSubstitute.Substitute.For <ISagaFactory <DummySaga, DummySagaState> >(); sagaFactory.Create(state) .Returns(saga); var sagaStateService = NSubstitute.Substitute.For <ISagaStateService <DummySaga, DummySagaState> >(); sagaStateService.GetAsync(messageContext, Arg.Any <CancellationToken>()) .Returns((state, Guid.NewGuid())); var logger = NSubstitute.Substitute.For <ILogger <SagaRunner <DummySaga, DummySagaState> > >(); var transactionManager = NSubstitute.Substitute.For <ITransactionManager>(); var policyFactory = NSubstitute.Substitute.For <ISagaPolicyFactory <DummySaga> >(); var sut = new SagaRunner <DummySaga, DummySagaState>(sagaFactory, sagaStateService, transactionManager, policyFactory, logger); await sut.RunAsync(messageContext, CancellationToken.None); sagaFactory.DidNotReceiveWithAnyArgs().Create(null); await saga.DidNotReceiveWithAnyArgs() .HandleAsync(messageContext, Arg.Any <CancellationToken>()); }
public async Task RunAsync_should_not_execute_handler_if_message_already_processed() { var message = new StartDummySaga(Guid.NewGuid(), Guid.NewGuid()); var messageContext = NSubstitute.Substitute.For <IMessageContext <StartDummySaga> >(); messageContext.Message.Returns(message); var saga = NSubstitute.Substitute.ForPartsOf <DummySaga>(); saga.When(s => s.HandleAsync(Arg.Any <IMessageContext <StartDummySaga> >(), Arg.Any <CancellationToken>())) .DoNotCallBase(); var state = new DummySagaState(message.CorrelationId); state.SetAsProcessed(message); var sagaFactory = NSubstitute.Substitute.For <ISagaFactory <DummySaga, DummySagaState> >(); sagaFactory.Create(state) .Returns(saga); var sagaStateService = NSubstitute.Substitute.For <ISagaStateService <DummySaga, DummySagaState> >(); sagaStateService.GetAsync(messageContext, Arg.Any <CancellationToken>()) .Returns((state, Guid.NewGuid())); var logger = NSubstitute.Substitute.For <ILogger <SagaRunner <DummySaga, DummySagaState> > >(); var uow = NSubstitute.Substitute.For <IUnitOfWork>(); var sut = new SagaRunner <DummySaga, DummySagaState>(sagaFactory, sagaStateService, uow, logger); await sut.RunAsync(messageContext, CancellationToken.None); sagaFactory.DidNotReceiveWithAnyArgs().Create(null); await saga.DidNotReceiveWithAnyArgs() .HandleAsync(messageContext, Arg.Any <CancellationToken>()); }
public async Task SaveAsync_should_persist_outbox() { var sagaStateFactory = NSubstitute.Substitute.For <ISagaStateFactory <DummySagaState> >(); var sagaStateRepo = NSubstitute.Substitute.For <ISagaStateRepository>(); var outboxRepository = NSubstitute.Substitute.For <IOutboxRepository>(); var sut = new SagaStateService <DummySaga, DummySagaState>(sagaStateFactory, sagaStateRepo, outboxRepository); var state = new DummySagaState(Guid.NewGuid()); var message = StartDummySaga.New(); state.AddToOutbox(message); var lockId = Guid.NewGuid(); await sut.SaveAsync(state, lockId, CancellationToken.None); await outboxRepository.Received(1) .AppendAsync(message, Arg.Any <CancellationToken>()); }
public async Task RunAsync_should_throw_SagaNotFoundException_if_saga_cannot_be_build() { var message = new StartDummySaga(Guid.NewGuid(), Guid.NewGuid()); var messageContext = NSubstitute.Substitute.For <IMessageContext <StartDummySaga> >(); messageContext.Message.Returns(message); var sagaFactory = NSubstitute.Substitute.For <ISagaFactory <DummySaga, DummySagaState> >(); var sagaStateService = NSubstitute.Substitute.For <ISagaStateService <DummySaga, DummySagaState> >(); var state = new DummySagaState(message.CorrelationId); sagaStateService.GetAsync(messageContext, Arg.Any <CancellationToken>()) .Returns((state, Guid.NewGuid())); var logger = NSubstitute.Substitute.For <ILogger <SagaRunner <DummySaga, DummySagaState> > >(); var uow = NSubstitute.Substitute.For <IUnitOfWork>(); var sut = new SagaRunner <DummySaga, DummySagaState>(sagaFactory, sagaStateService, uow, logger); await Assert.ThrowsAsync <SagaNotFoundException>(() => sut.RunAsync(messageContext, CancellationToken.None)); }
public void IsCompleted_should_return_false_when_state_is_initialized_first_time() { var state = new DummySagaState(Guid.NewGuid()); state.IsCompleted().Should().BeFalse(); }
public void CheckWasProcessed_should_throw_ArgumentNullException_if_message_null() { var sut = new DummySagaState(Guid.NewGuid()); Assert.Throws <ArgumentNullException>(() => sut.CheckWasProcessed((IMessage)null)); }