public async Task Should_handle_in_other_order() { var reservationId = NewId.NextGuid(); var bookId = NewId.NextGuid(); var memberId = NewId.NextGuid(); await TestHarness.Bus.Publish <BookCheckedOut>(new { CheckOutId = InVar.Id, bookId, memberId, InVar.Timestamp }); Assert.IsTrue(await SagaHarness.Consumed.Any <BookCheckedOut>(x => x.Context.Message.BookId == bookId), "Message not consumed by saga"); Assert.That(await SagaHarness.Created.Any(x => x.Saga.BookId == bookId), "Saga not created"); ISagaInstance <ThankYou> instance = SagaHarness.Created.Select(x => x.Saga.BookId == bookId).First(); await TestHarness.Bus.Publish <BookReserved>(new { bookId, memberId, reservationId, Duration = TimeSpan.FromDays(14), InVar.Timestamp }); Assert.IsTrue(await SagaHarness.Consumed.Any <BookReserved>(x => x.Context.Message.BookId == bookId), "Message not consumed by saga"); Guid?existsId = await SagaHarness.Exists(instance.Saga.CorrelationId, x => x.Ready); Assert.IsTrue(existsId.HasValue, "Saga did not transition to Ready"); }
public async Task Should_Create_A_Saga_Instance() { var reservationId = NewId.NextGuid(); var bookId = NewId.NextGuid(); var memberId = NewId.NextGuid(); await TestHarness.Bus.Publish <IReservationRequestedGlobalEvent>(new { ReservationId = reservationId, Timestamp = InVar.Timestamp, MemberId = memberId, BookId = bookId }); (await TestHarness.Consumed.Any <IReservationRequestedGlobalEvent>()).Should() .BeTrue("Message should be consumed by normal bus!"); (await SagaHarness.Consumed.Any <IReservationRequestedGlobalEvent>()).Should() .BeTrue("Message should be consumed by saga!"); //(await SagaHarness.Created.Any(x => x.CorrelationId == reservationId)).Should() // .BeTrue("A reservation saga state machine instance should be created!"); SagaHarness.Created.ContainsInState(reservationId, Machine, Machine.Requested).Should() .NotBeNull("A reservation saga state machine instance should be created!"); (await SagaHarness.Exists(reservationId, x => x.Requested)).HasValue.Should() .BeTrue("Reservation saga instance should exist!"); }
public async Task Should_handle_the_fault_message_via_correlation() { var bookId = NewId.NextGuid(); var checkOutId = NewId.NextGuid(); var memberId = NewId.NextGuid(); await TestHarness.Bus.Publish <BookCheckedOut>(new { CheckOutId = checkOutId, BookId = bookId, InVar.Timestamp, MemberId = memberId }); var existsId = await SagaHarness.Exists(checkOutId, x => x.CheckedOut); Assert.IsTrue(existsId.HasValue, "Saga did not exist"); Assert.IsTrue(await TestHarness.Published.Any <AddBookToMemberCollection>(), "Add to collection not published"); Assert.IsTrue(await TestHarness.Consumed.Any <AddBookToMemberCollection>(), "Add not consumed"); Assert.IsTrue(await TestHarness.Published.Any <Fault <AddBookToMemberCollection> >(), "Fault not published"); Assert.IsTrue(await TestHarness.Consumed.Any <Fault <AddBookToMemberCollection> >(), "Fault not consumed"); }
public async Task Should_renew_an_existing_checkout() { var bookId = NewId.NextGuid(); var checkOutId = NewId.NextGuid(); DateTime now = DateTime.UtcNow; await TestHarness.Bus.Publish <BookCheckedOut>(new { CheckOutId = checkOutId, BookId = bookId, InVar.Timestamp, MemberId = NewId.NextGuid() }); var existsId = await SagaHarness.Exists(checkOutId, x => x.CheckedOut); Assert.IsTrue(existsId.HasValue, "Saga did not exist"); using var scope = Provider.CreateScope(); var requestClient = scope.ServiceProvider.GetRequiredService <IRequestClient <RenewCheckOut> >(); now = DateTime.UtcNow; var(renewed, notFound) = await requestClient.GetResponse <CheckOutRenewed, CheckOutNotFound>(new { checkOutId }); if (renewed.IsCompletedSuccessfully) { var response = await renewed; Assert.That(response.Message.DueDate, Is.GreaterThanOrEqualTo(now + TimeSpan.FromDays(14))); } Assert.That(notFound.IsCompletedSuccessfully, Is.False); }
public async Task Should_change_state_to_checked_out() { var bookId = NewId.NextGuid(); await TestHarness.Bus.Publish <BookAdded>(new { BookId = bookId, Isbn = "0307969959", Title = "Neuromancer" }); var existsId = await SagaHarness.Exists(bookId, x => x.Available); Assert.IsTrue(existsId.HasValue, "Saga did not exist"); await TestHarness.Bus.Publish <BookCheckedOut>(new { BookId = bookId, InVar.Timestamp }); existsId = await SagaHarness.Exists(bookId, x => x.CheckedOut); Assert.IsTrue(existsId.HasValue, "Saga was not checked out"); }
public async Task Should_create_a_saga_instance() { var bookId = NewId.NextGuid(); var checkOutId = NewId.NextGuid(); DateTime now = DateTime.UtcNow; await TestHarness.Bus.Publish <BookCheckedOut>(new { CheckOutId = checkOutId, BookId = bookId, InVar.Timestamp, MemberId = NewId.NextGuid() }); Assert.IsTrue(await TestHarness.Consumed.Any <BookCheckedOut>(), "Message not consumed"); Assert.IsTrue(await SagaHarness.Consumed.Any <BookCheckedOut>(), "Message not consumed by saga"); Assert.That(await SagaHarness.Created.Any(x => x.CorrelationId == checkOutId)); var instance = SagaHarness.Created.ContainsInState(checkOutId, Machine, Machine.CheckedOut); Assert.IsNotNull(instance, "Saga instance not found"); Assert.That(instance.DueDate, Is.GreaterThanOrEqualTo(now + TimeSpan.FromDays(14))); var existsId = await SagaHarness.Exists(checkOutId, x => x.CheckedOut); Assert.IsTrue(existsId.HasValue, "Saga did not exist"); Assert.IsTrue(await TestHarness.Published.Any <NotifyMemberDueDate>(), "Due Date Event Not Published"); }
public async Task Should_handle_the_request_fault() { var checkOutId = NewId.NextGuid(); var bookId = NewId.NextGuid(); var memberId = NewId.NextGuid(); var now = DateTime.UtcNow; await TestHarness.Bus.Publish <BookReturned>(new { CheckOutId = checkOutId, InVar.Timestamp, BookId = bookId, MemberId = memberId, CheckOutDate = now - TimeSpan.FromDays(28), DueDate = now - TimeSpan.FromDays(14), ReturnDate = now, }); Guid?existsId = await SagaHarness.Exists(checkOutId, x => x.ChargingFine); Assert.IsTrue(existsId.HasValue, "Saga did not exist"); Assert.IsTrue(await TestHarness.Consumed.Any <ChargeMemberFine>(), "Fine not consumed"); Assert.IsTrue(await TestHarness.Consumed.Any <Fault <ChargeMemberFine> >(), "Fine charged"); }
public async Task ReservationSaga가_생성된다() { var bookId = NewId.NextGuid(); var reservationId = NewId.NextGuid(); var memberId = NewId.NextGuid(); await TestHarness.Bus.Publish <ReservationRequested>(new { ReservationId = reservationId, Timestamp = InVar.Timestamp, MemberId = memberId, BookId = bookId }); // 실제로 Message를 Serialize 하고, 전송하는 모든 과정이 Simulation 된다. Assert.IsTrue(await TestHarness.Consumed.Any <ReservationRequested>(), "메시지 수신이 안됨"); Assert.IsTrue(await SagaHarness.Consumed.Any <ReservationRequested>(), "Saga에 의해 메시지 처리가 안됨"); Assert.That(await SagaHarness.Created.Any(x => x.CorrelationId == reservationId), "생성된 Saga의 CorrelationId 는 Reservation Id 여야 함"); // var instance = SagaHarness.Created.ContainsInState(bookId, StateMachine, StateMachine.Available); // var wrongBookId = NewId.NextGuid(); Assert.That(await SagaHarness.Exists(reservationId, machine => machine.Requested), Is.EqualTo(reservationId), "수신된 메시지의 BookId 에 해당하는 Requested 상태의 Saga가 없음."); }
public async Task Should_create_a_saga_instance() { var reservationId = NewId.NextGuid(); var bookId = NewId.NextGuid(); var memberId = NewId.NextGuid(); await TestHarness.Bus.Publish <ReservationRequested>(new { ReservationId = reservationId, InVar.Timestamp, MemberId = memberId, BookId = bookId, }); Assert.IsTrue(await TestHarness.Consumed.Any <ReservationRequested>(), "Message not consumed"); Assert.IsTrue(await SagaHarness.Consumed.Any <ReservationRequested>(), "Message not consumed by saga"); Assert.That(await SagaHarness.Created.Any(x => x.CorrelationId == reservationId)); var instance = SagaHarness.Created.ContainsInState(reservationId, Machine, Machine.Requested); Assert.IsNotNull(instance, "Saga instance not found"); var existsId = await SagaHarness.Exists(reservationId, x => x.Requested); Assert.IsTrue(existsId.HasValue, "Saga did not exist"); }
public async Task Should_create_a_saga_instance() { var bookId = NewId.NextGuid(); await TestHarness.Bus.Publish <BookAdded>(new { BookId = bookId, Isbn = "0307969959", Title = "Neuromancer" }); Assert.IsTrue(await TestHarness.Consumed.Any <BookAdded>(), "Message not consumed"); Assert.IsTrue(await SagaHarness.Consumed.Any <BookAdded>(), "Message not consumed by saga"); Assert.That(await SagaHarness.Created.Any(x => x.CorrelationId == bookId)); var instance = SagaHarness.Created.ContainsInState(bookId, Machine, Machine.Available); Assert.IsNotNull(instance, "Saga instance not found"); var existsId = await SagaHarness.Exists(bookId, x => x.Available); Assert.IsTrue(existsId.HasValue, "Saga did not exist"); }
public async Task Should_mark_state_as_captured_when_payment_is_captured() { var paymentId = NewId.NextGuid(); await TestHarness.Bus.Publish <IPaymentAuthorized>(new { PaymentId = paymentId, AuthorizationCode = "PASS", TransactionId = "2452354325", AuthorizationExpiration = TimeSpan.FromHours(6) }); Assert.That(SagaHarness.Created.Select(x => x.CorrelationId == paymentId).Any(), Is.True); var instanceId = await SagaHarness.Exists(paymentId, x => x.Authorized); Assert.That(instanceId, Is.Not.Null); var instance = SagaHarness.Sagas.Contains(instanceId.Value); Assert.That(instance.AuthorizationCode, Is.EqualTo("PASS")); Assert.That(instance.TransactionId, Is.EqualTo("2452354325")); await TestHarness.Bus.Publish <IPaymentCaptured>(new { TransactionId = "2452354325" }); instanceId = await SagaHarness.Exists(paymentId, x => x.Captured); Assert.That(instanceId, Is.Not.Null); }
public async Task Should_not_reserve_the_book() { var reservationId = NewId.NextGuid(); var bookId = NewId.NextGuid(); var memberId = NewId.NextGuid(); await TestHarness.Bus.Publish <BookAdded>(new { BookId = bookId, Isbn = "0307969959", Title = "Neuromancer" }); var existsId = await _bookSagaHarness.Exists(bookId, x => x.Available); Assert.IsTrue(existsId.HasValue, "Saga did not exist"); await TestHarness.Bus.Publish <ReservationRequested>(new { ReservationId = reservationId, InVar.Timestamp, MemberId = memberId, BookId = bookId, }); existsId = await SagaHarness.Exists(reservationId, x => x.Reserved); Assert.IsTrue(existsId.HasValue, "Saga did not exist"); var reservation = SagaHarness.Sagas.ContainsInState(reservationId, Machine, x => x.Reserved); Assert.IsNotNull(reservation, "Reservation did not exist"); var secondReservationId = NewId.NextGuid(); await TestHarness.Bus.Publish <ReservationRequested>(new { ReservationId = secondReservationId, InVar.Timestamp, MemberId = NewId.NextGuid(), BookId = bookId, }); existsId = await SagaHarness.Exists(secondReservationId, x => x.Requested); Assert.IsTrue(existsId.HasValue, "Saga did not exist"); var secondReservation = SagaHarness.Sagas.ContainsInState(secondReservationId, Machine, x => x.Requested); Assert.IsNotNull(secondReservation, "Reservation did not exist"); }
public async Task Should_mark_book_as_available() { var reservationId = NewId.NextGuid(); var bookId = NewId.NextGuid(); var memberId = NewId.NextGuid(); await TestHarness.Bus.Publish <BookAdded>(new { BookId = bookId, Isbn = "0307969959", Title = "Neuromancer" }); var existsId = await _bookSagaHarness.Exists(bookId, x => x.Available); Assert.IsTrue(existsId.HasValue, "Saga did not exist"); await TestHarness.Bus.Publish <ReservationRequested>(new { ReservationId = reservationId, InVar.Timestamp, Duration = TimeSpan.FromDays(2), MemberId = memberId, BookId = bookId, }); existsId = await SagaHarness.Exists(reservationId, x => x.Reserved); Assert.IsTrue(existsId.HasValue, "Reservation was not reserved"); existsId = await _bookSagaHarness.Exists(bookId, x => x.Reserved); Assert.IsTrue(existsId.HasValue, "Saga did not exist"); await AdvanceSystemTime(TimeSpan.FromHours(24)); existsId = await SagaHarness.Exists(reservationId, x => x.Reserved); Assert.IsTrue(existsId.HasValue, "Reservation was not still reserved"); await AdvanceSystemTime(TimeSpan.FromHours(24)); Guid?notExists = await SagaHarness.NotExists(reservationId); Assert.IsFalse(notExists.HasValue); existsId = await _bookSagaHarness.Exists(bookId, x => x.Available); Assert.IsTrue(existsId.HasValue, "Saga did not exist"); }
public async Task The_reservation_should_be_removed() { var reservationId = NewId.NextGuid(); var bookId = NewId.NextGuid(); var memberId = NewId.NextGuid(); await TestHarness.Bus.Publish <BookAdded>(new { BookId = bookId, Isbn = "0307969959", Title = "Neuromancer" }); var existsId = await _bookSagaHarness.Exists(bookId, x => x.Available); Assert.IsTrue(existsId.HasValue, "Saga did not exist"); await TestHarness.Bus.Publish <ReservationRequested>(new { ReservationId = reservationId, InVar.Timestamp, MemberId = memberId, BookId = bookId, }); existsId = await SagaHarness.Exists(reservationId, x => x.Reserved); Assert.IsTrue(existsId.HasValue, "Reservation was not reserved"); existsId = await _bookSagaHarness.Exists(bookId, x => x.Reserved); Assert.IsTrue(existsId.HasValue, "Saga did not exist"); await TestHarness.Bus.Publish <BookCheckedOut>(new { BookId = bookId, InVar.Timestamp }); Guid?notExists = await SagaHarness.NotExists(reservationId); Assert.IsFalse(notExists.HasValue); existsId = await _bookSagaHarness.Exists(bookId, x => x.CheckedOut); Assert.IsTrue(existsId.HasValue, "Book was not checked out"); }
public async Task Should_renew_an_existing_checkout_up_to_the_limit() { var bookId = NewId.NextGuid(); var checkOutId = NewId.NextGuid(); DateTime now = DateTime.UtcNow; DateTime checkedOutAt = DateTime.UtcNow; await TestHarness.Bus.Publish <BookCheckedOut>(new { CheckOutId = checkOutId, BookId = bookId, InVar.Timestamp, MemberId = NewId.NextGuid() }); var existsId = await SagaHarness.Exists(checkOutId, x => x.CheckedOut); Assert.IsTrue(existsId.HasValue, "Saga did not exist"); using var scope = Provider.CreateScope(); var requestClient = scope.ServiceProvider.GetRequiredService <IRequestClient <RenewCheckOut> >(); now = DateTime.UtcNow; using var request = requestClient.Create(new { checkOutId }); var renewed = request.GetResponse <CheckOutRenewed>(false); var notFound = request.GetResponse <CheckOutNotFound>(false); var limitReached = request.GetResponse <CheckOutDurationLimitReached>(); Task whenAny = await Task.WhenAny(renewed, notFound, limitReached); Assert.That(notFound.IsCompletedSuccessfully, Is.False); Assert.That(renewed.IsCompletedSuccessfully, Is.False); Assert.That(limitReached.IsCompletedSuccessfully, Is.True); if (limitReached.IsCompletedSuccessfully) { var response = await limitReached; Assert.That(response.Message.DueDate, Is.LessThan(now + TimeSpan.FromDays(14))); Assert.That(response.Message.DueDate, Is.GreaterThanOrEqualTo(checkedOutAt + TimeSpan.FromDays(13))); } }
public async Task Book을_예약해야_한다() { var bookId = NewId.NextGuid(); var reservationId = NewId.NextGuid(); var memberId = NewId.NextGuid(); var isbn = "1234567"; var bookAddedAt = new DateTime(2020, 12, 11); var bookRequestedAt = new DateTime(2020, 12, 25); await TestHarness.Bus.Publish <BookAdded>(new { BookId = bookId, Timestamp = bookAddedAt, Isbn = isbn, Title = "Gone with the Wind" }); var existId = await BookSagaHarness.Exists(bookId, machine => machine.Available); Assert.IsTrue(existId.HasValue); await TestHarness.Bus.Publish <ReservationRequested>(new { ReservationId = reservationId, Timestamp = bookRequestedAt, MemberId = memberId, BookId = bookId }); // 실제로 Message를 Serialize 하고, 전송하는 모든 과정이 Simulation 된다. // 이런식으로 하면, Timing Issue가 있을 수 있다. // Assert.IsNotNull(SagaHarness.Sagas.ContainsInState(reservationId, StateMachine, x => x.Reserved)); Assert.That(await SagaHarness.Exists(reservationId, machine => machine.Reserved), Is.EqualTo(reservationId), "ReservationSaga 가 Reserved 상태가 아님"); // Assert.IsNotEmpty(SagaHarness.Sagas.Select(context => // context.CorrelationId == reservationId && // context.RequestedAt == bookRequestedAt // )); }
public async Task 새로운_BookId_메시지를_받으면_새로운_Saga_Instance가_만들어진다() { var bookId = NewId.NextGuid(); await TestHarness.Bus.Publish <BookAdded>(new { BookId = bookId, Isbn = "0307959123", Title = "Gone with the Wind" }); // 실제로 Message를 Serialize 하고, 전송하는 모든 과정이 Simulation 된다. Assert.IsTrue(await TestHarness.Consumed.Any <BookAdded>(), "메시지 수신이 안됨"); Assert.IsTrue(await SagaHarness.Consumed.Any <BookAdded>(), "Saga에 의해 메시지 처리가 안됨"); Assert.That(await SagaHarness.Created.Any(x => x.CorrelationId == bookId), "생성된 Saga의 CorrelationId 는 Book Id 여야 함"); // var instance = SagaHarness.Created.ContainsInState(bookId, StateMachine, StateMachine.Available); // var wrongBookId = NewId.NextGuid(); Assert.That(await SagaHarness.Exists(bookId, machine => machine.Available), Is.EqualTo(bookId), "수신된 메시지의 BookId 에 해당하는 Saga가 없음."); }
public async Task Should_Mark_Book_As_Available() { var reservationId = NewId.NextGuid(); var bookId = NewId.NextGuid(); var memberId = NewId.NextGuid(); await TestHarness.Bus.Publish <IBookAddedGlobalEvent>(new { BookId = bookId, Isbn = "0307969959", Title = "Neuromancer" }); (await _bookSagaHarness.Exists(bookId, x => x.Available)).HasValue.Should() .BeTrue("Book Saga state machine should be existed at Available State!"); await TestHarness.Bus.Publish <IReservationRequestedGlobalEvent>(new { ReservationId = reservationId, Timestamp = InVar.Timestamp, MemberId = memberId, BookId = bookId }); (await SagaHarness.Exists(reservationId, x => x.Reserved)).HasValue.Should() .BeTrue("Reservation Saga state machine should be existed at Reserved State!"); (await _bookSagaHarness.Exists(bookId, x => x.Reserved)).HasValue.Should() .BeTrue("Book Saga state machine should be existed at Reserved State!"); // Turn the clock toward 24 hours await AdvanceSystemTime(TimeSpan.FromHours(24)); (await SagaHarness.NotExists(reservationId)).HasValue.Should().BeFalse( "The Reservation state machine should be finalized already cause of reservation expired itself!"); (await _bookSagaHarness.Exists(bookId, x => x.Available)).HasValue.Should().BeTrue( "Book Saga state machine should be existed at Available State cause the reservation was expired!"); }
public async Task Should_Reserved_The_Book() { var reservationId = NewId.NextGuid(); var bookId = NewId.NextGuid(); var memberId = NewId.NextGuid(); await TestHarness.Bus.Publish <IBookAddedGlobalEvent>(new { BookId = bookId, Isbn = "0307969959", Title = "Neuromancer" }); var existsId = await _bookSagaHarness.Exists(bookId, x => x.Available); existsId.HasValue.Should().BeTrue("Book saga state instance should exists!"); await TestHarness.Bus.Publish <IReservationRequestedGlobalEvent>(new { ReservationId = reservationId, Timestamp = InVar.Timestamp, MemberId = memberId, BookId = bookId }); (await SagaHarness.Consumed.Any <IReservationRequestedGlobalEvent>()).Should() .BeTrue("Message should be consumed by Reservation Saga!"); (await _bookSagaHarness.Consumed.Any <IReservationRequestedGlobalEvent>()).Should() .BeTrue("Message should be consumed by Book Saga!"); existsId = await SagaHarness.Exists(reservationId, x => x.Reserved); existsId.HasValue.Should().BeTrue("Reservation saga state instance should exists!"); SagaHarness.Sagas.ContainsInState(reservationId, Machine, x => x.Reserved).Should() .NotBeNull("Reservation saga state instance should exists on [Reserved] state!"); }
public async Task Should_Create_A_Saga_Instance() { var bookId = NewId.NextGuid(); await TestHarness.Bus.Publish <IBookAddedGlobalEvent>(new { BookId = bookId, Isbn = "0307969959", Title = "Neuromancer" }); (await TestHarness.Consumed.Any <IBookAddedGlobalEvent>()).Should() .BeTrue($"The {nameof(IBookAddedGlobalEvent)} should be consumed by Masstransit!"); (await SagaHarness.Consumed.Any <IBookAddedGlobalEvent>()).Should() .BeTrue($"The {nameof(IBookAddedGlobalEvent)} should be consumed by Saga!"); (await SagaHarness.Created.Any(x => x.CorrelationId == bookId)).Should() .BeTrue("The correlationId of the book should be match!"); SagaHarness.Created.ContainsInState(bookId, Machine, Machine.Available).Should() .NotBeNull("Saga instance of the book should be exists!"); (await SagaHarness.Exists(bookId, x => x.Available)).HasValue.Should() .BeTrue("Saga instance should exists!"); Output.Information("Ran in here"); }