예제 #1
0
        public void Onboarding_Causes_An_Account_To_Be_Created_For_The_Customer()
        {
            var customerName = RandomName;
            var bus          = new FakeBus();

            using (var fixture = SagaFixture.For(() => new OnboardCustomerSaga(bus)))
            {
                fixture.Deliver(new OnboardCustomer {
                    CustomerName = customerName
                });
                fixture.SagaDataShould(
                    have: x => x.CustomerName == customerName,
                    because: "store the customer name")
                .SagaDataIsNotComplete();
                bus.HasSentLocal <CreateCustomerAccount>(
                    with: x => x.CustomerName == customerName,
                    because: "it should initiate account creation"
                    );


                fixture.Deliver(new CustomerAccountCreated {
                    CustomerName = customerName
                });
                fixture.SagaDataShould(
                    have: x => x.AccountCreated,
                    because: "it should remember the account has been created")
                .SagaDataIsNotComplete();

                fixture.ShouldNotHaveCompleted();
            }
        }
예제 #2
0
        public void CanCorrectlySerializeAndDeserializeCaspersSagaData()
        {
            // arrange
            var fixture = new SagaFixture <SagaData>(new Saga());

            // act
            fixture.Handle(new Message {
                CorrelationId = 42, String = "hello there"
            });
            fixture.Handle(new Message {
                CorrelationId = 42, String = "hello again!"
            });

            // assert
            fixture.AvailableSagaData.Count()
            .ShouldBe(1);

            var sagaData = fixture.AvailableSagaData.Single();

            sagaData.ReceivedStrings.ShouldContain("hello there");
            sagaData.ReceivedStrings.ShouldContain("hello again!");

            var concreteClass = (ConcreteClass)sagaData.RefToAbstractClass;

            concreteClass.WithWhat.ShouldBe("something in it");
        }
예제 #3
0
        public void CanSimulateConflict_MultipleMessages_SingleConflict()
        {
            using (var fixture = SagaFixture.For(() => new ConflictSagaHandler()))
            {
                fixture.DumpLogsOnDispose();

                fixture.Deliver(new SomeMessage("some-id", "HEJ MED DIG"));
                fixture.Deliver(new SomeMessage("some-id", "MIN VEN"));

                fixture.PrepareConflict <ConflictSagaHandlerData>(d => d.CorrelationId == "some-id");

                fixture.Deliver(new SomeMessage("some-id", "IGEN"));

                var sagaData = fixture.Data
                               .OfType <ConflictSagaHandlerData>()
                               .FirstOrDefault(d => d.CorrelationId == "some-id")
                               ?? throw new AssertionException($"Could not find saga data with correlation ID 'some-id'");

                string GetReceivedStrings() =>
                $@"Got these strings:

{string.Join(Environment.NewLine, sagaData.ReceivedStrings)}
";

                Assert.That(sagaData.ReceivedStrings.Count, Is.EqualTo(3), GetReceivedStrings);
                Assert.That(sagaData.ReceivedStrings.Contains("HEJ MED DIG"), Is.True, GetReceivedStrings);
                Assert.That(sagaData.ReceivedStrings.Contains("MIN VEN"), Is.True, GetReceivedStrings);
                Assert.That(sagaData.ReceivedStrings.Contains("IGEN"), Is.True, GetReceivedStrings);
            }
        }
예제 #4
0
        public void The_Sales_Team_Will_Set_Up_A_Call_With_The_Customer_After_Their_Account_Has_Been_Created()
        {
            var customerName = RandomName;
            var bus          = new FakeBus();

            using (var fixture = SagaFixture.For(() => new OnboardCustomerSaga(bus)))
            {
                fixture.Deliver(new OnboardCustomer {
                    CustomerName = customerName
                });
                fixture.Deliver(new CustomerAccountCreated {
                    CustomerName = customerName
                });
                fixture.SagaDataShould(
                    have: x => x.AccountCreated,
                    because: "it should remember the account has been created")
                .SagaDataIsNotComplete();

                bus.HasSentLocal <ScheduleASalesCall>(
                    with: x => x.CustomerName == customerName,
                    because: "a sales call is scheduled after the account is created");

                fixture.ShouldNotHaveCompleted();
            }
        }
예제 #5
0
        public void Other_Systems_Are_Notified_After_A_Succcessful_Onboarding()
        {
            var customerName = RandomName;
            var bus          = new FakeBus();

            using (var fixture = SagaFixture.For(() => new OnboardCustomerSaga(bus)))
            {
                fixture.Deliver(new OnboardCustomer {
                    CustomerName = customerName
                });
                fixture.Deliver(new CustomerAccountCreated {
                    CustomerName = customerName
                });
                fixture.Deliver(new WelcomePackSentToCustomer {
                    CustomerName = customerName
                });
                fixture.ShouldHaveCompleted();
                bus.HasPublished <CustomerOnboarded>(
                    with: x => x.CustomerName == customerName,
                    because: "the saga should publishes an event notifying of the customer onboarding")
                .HasNotSentLocal <CustomerOnboardingOlaBreached>(
                    because: "the onboarding was successful");

                fixture.ShouldHaveCompleted();

                OnboardCustomerSagaData SagaDataShould(Predicate <OnboardCustomerSagaData> have, string because = null)
                {
                    return(fixture.SagaData <OnboardCustomerSaga, OnboardCustomerSagaData>().Should(have, because));
                }
            }
        }
예제 #6
0
        public void CanCorrelateMessagesLikeExpected()
        {
            // arrange
            var fixture = new SagaFixture <SomeSagaData>(new SomeSaga());

            fixture.CreatedNewSagaData             += (message, data) => Console.WriteLine("Created new saga data");
            fixture.CorrelatedWithExistingSagaData += (message, data) => Console.WriteLine("Correlated with existing saga data");
            fixture.CouldNotCorrelate += message => Console.WriteLine("Could not correlate");

            // act
            fixture.Handle(new SomeMessage {
                SagaDataId = 10
            });
            fixture.Handle(new SomeMessage {
                SagaDataId = 10
            });
            fixture.Handle(new SomeMessage {
                SagaDataId = 12
            });
            fixture.Handle(new SomeMessage {
                SagaDataId = 12
            });
            fixture.Handle(new SomeMessage {
                SagaDataId = 12
            });

            // assert
            var availableSagaData = fixture.AvailableSagaData;

            availableSagaData.Count().ShouldBe(2);
            availableSagaData.Single(d => d.SagaDataId == 10).ReceivedMessages.ShouldBe(2);
            availableSagaData.Single(d => d.SagaDataId == 12).ReceivedMessages.ShouldBe(3);
        }
예제 #7
0
        public void A_Welcome_Pack_Is_Sent_To_The_Customer_After_Their_Account_Has_Been_Created()
        {
            var customerName = RandomName;
            var bus          = new FakeBus();

            using (var fixture = SagaFixture.For(() => new OnboardCustomerSaga(bus)))
            {
                fixture.Deliver(new OnboardCustomer {
                    CustomerName = customerName
                });
                fixture.Deliver(new CustomerAccountCreated {
                    CustomerName = customerName
                });

                fixture.SagaDataShould(
                    have: x => x.AccountCreated,
                    because: "it should remember the account has been created")
                .SagaDataIsNotComplete();
                bus.HasSent <SendWelcomePackToCustomer>(
                    with: x => x.CustomerName == customerName,
                    because: "it should initiate welcome pack creation"
                    );

                fixture.ShouldNotHaveCompleted();
            }
        }
예제 #8
0
        public void CanCorrectlyHandleWhenSagaIsMarkedAsComplete()
        {
            // arrange
            var          fixture = new SagaFixture <CompletionSagaData>(new CompletionSaga());
            const string justTheSameFrigginId = "just the same friggin ID";

            var sagaDatasMarkedAsComplete = new List <ISagaData>();

            fixture.MarkedAsComplete += (message, data) => sagaDatasMarkedAsComplete.Add(data);
            fixture.CorrelatedWithExistingSagaData += (message, data) => Console.WriteLine("Correlated!");
            fixture.CouldNotCorrelate  += message => Console.WriteLine("Could not correlate!");
            fixture.CreatedNewSagaData += (message, data) => Console.WriteLine("Created new!");
            fixture.Exception          += (message, exception) => Console.WriteLine("Exception!");

            // act
            fixture.Handle(new InitiatingMessage {
                CorrelationId = justTheSameFrigginId
            });
            fixture.Handle(new CompletionMessage {
                CorrelationId = justTheSameFrigginId
            });
            fixture.Handle(new InitiatingMessage {
                CorrelationId = justTheSameFrigginId
            });
            fixture.Handle(new CompletionMessage {
                CorrelationId = justTheSameFrigginId
            });

            // assert
            sagaDatasMarkedAsComplete.Count.ShouldBe(2);
            fixture.DeletedSagaData.Count.ShouldBe(2);
        }
예제 #9
0
        public void EventAreFiredInTheRightPlaces(string scenario)
        {
            var          events = new List <string>();
            const string justTheSameFrigginId = "just the same friggin ID";

            var fixture = new SagaFixture <CompletionSagaData>(new CompletionSaga());

            fixture.MarkedAsComplete += (msg, data) => events.Add("markedAsComplete");

            switch (scenario)
            {
            case "mark persistent saga data as complete":
                fixture.Handle(new InitiatingMessage {
                    CorrelationId = justTheSameFrigginId
                });
                fixture.Handle(new CompletionMessage {
                    CorrelationId = justTheSameFrigginId
                });
                break;

            case "mark non-persistent saga data as complete":
                fixture.Handle(new InitiateAndCompleteMessage {
                    CorrelationId = justTheSameFrigginId
                });
                break;

            default:
                throw new ArgumentException(string.Format("Unknown scenario: {0}", scenario));
            }

            events.ShouldContain("markedAsComplete");
        }
예제 #10
0
        public void WorksWhenMessageReferenceIsOfTheSupertype()
        {
            // arrange
            var data = new CounterpartData {
                Dcid = 800
            };
            var calledHandlers = new List <string>();
            var fixture        = new SagaFixture <CounterpartData>(new CounterpartUpdater(calledHandlers));

            fixture.AddSagaData(data);
            CounterpartChanged messageSupertype1 = new CounterpartCreated {
                Dcid = 800
            };
            CounterpartChanged messageSupertype2 = new CounterpartUpdated {
                Dcid = 800
            };

            // act
            // assert
            fixture.Handle(messageSupertype1);
            fixture.Handle(messageSupertype2);

            calledHandlers.ShouldBe(new List <string>
            {
                "CounterpartCreated",
                "CounterpartUpdated",
            });
        }
예제 #11
0
        public void If_The_Ola_Is_Breached_Then_Any_Placed_Sales_Call_Is_Cancelled()
        {
            var customerName = RandomName;
            var bus          = new FakeBus();

            using (var fixture = SagaFixture.For(() => new OnboardCustomerSaga(bus)))
            {
                fixture.Deliver(new OnboardCustomer {
                    CustomerName = customerName
                });
                fixture.Deliver(new CustomerAccountCreated {
                    CustomerName = customerName
                });
                bus.HasSentLocal <ScheduleASalesCall>(
                    with: x => x.CustomerName == customerName,
                    because: "a sales call is scheduled after the account is created");

                fixture.Deliver(new VerifyCustomerOnboardingOla {
                    CustomerName = customerName
                });

                fixture.ShouldHaveCompleted();
                bus.HasSentLocal <CancellSalesCall>(
                    with: x => x.CustomerName == customerName,
                    because: "any scheduled sales call is cancelled after an OLA breach");
            }
        }
예제 #12
0
 public static void DumpLogsOnDispose <TSagaHandler>(this SagaFixture <TSagaHandler> sagaFixture)
     where TSagaHandler : Saga
 {
     sagaFixture.Disposed += () =>
     {
         Console.WriteLine(string.Join(Environment.NewLine, sagaFixture.LogEvents));
     };
 }
예제 #13
0
    public void CanRetrieveSagaData()
    {
        using var fixture = SagaFixture.For <MySaga>();

        fixture.Deliver(new TestMessage("hej"));

        var current = fixture.Data.OfType <MySagaState>().ToList();

        Assert.That(current.Count, Is.EqualTo(1));
        Assert.That(current[0].Text, Is.EqualTo("hej"));
    }
    public static void DumpLogsOnDispose <TSagaHandler>(this SagaFixture <TSagaHandler> sagaFixture) where TSagaHandler : Saga
    {
        if (sagaFixture == null)
        {
            throw new ArgumentNullException(nameof(sagaFixture));
        }

        sagaFixture.Disposed += () =>
        {
            Console.WriteLine(string.Join(Environment.NewLine, sagaFixture.LogEvents));
        };
    }
예제 #15
0
        public void EmitsCouldNotCorrelateEvent()
        {
            using (var fixture = SagaFixture.For <MySaga>())
            {
                var gotEvent = false;
                fixture.CouldNotCorrelate += () => gotEvent = true;

                fixture.Deliver(new TestMessage("hej"));

                Assert.That(gotEvent, Is.True);
            }
        }
    public void EmitsCreatedEvent()
    {
        using var fixture = SagaFixture.For(sagaHandlerFactory: () => new MySaga(), sagaSerializerFactory: () => new MicrosoftSagaSerializer());

        var gotEvent = false;

        fixture.Created += _ => gotEvent = true;

        fixture.Deliver(new TestMessage("hej"));

        Assert.That(gotEvent, Is.True);
    }
예제 #17
0
        public void EmitsCreatedEvent()
        {
            using (var fixture = SagaFixture.For <MySaga>())
            {
                var gotEvent = false;
                fixture.Created += d => gotEvent = true;

                fixture.Deliver(new TestMessage("hej"));

                Assert.That(gotEvent, Is.True);
            }
        }
예제 #18
0
        public void AddShouldAddToAvailableSagaData()
        {
            var someSagaData = new SomeSagaData {
                JustSomeText = Guid.NewGuid().ToString()
            };

            var fixture = new SagaFixture <SomeSagaData>(new SomeSaga())
            {
                someSagaData
            };

            fixture.OfType <SomeSagaData>().First().JustSomeText.ShouldBe(someSagaData.JustSomeText);
        }
예제 #19
0
    public void EmitsUpdatedEvent()
    {
        using var fixture = SagaFixture.For <MySaga>();

        fixture.Deliver(new TestMessage("hej"));

        var gotEvent = false;

        fixture.Updated += _ => gotEvent = true;

        fixture.Deliver(new TestMessage("hej"));

        Assert.That(gotEvent, Is.True);
    }
예제 #20
0
    public void Reproduce()
    {
        using var fixture = SagaFixture.For(() => new MySaga());

        fixture.DumpLogsOnDispose();

        fixture.Deliver(new MyMessage());

        Task.Delay(TimeSpan.FromSeconds(1)).Wait();

        var logs = fixture.LogEvents.ToList();

        Assert.That(logs.Count(l => l.Level == LogLevel.Warn), Is.EqualTo(1));
    }
예제 #21
0
        public void IdIsSetUponNullId()
        {
            using (var fixture = SagaFixture.For <MySaga>())
            {
                // Arrange

                // Act
                fixture.Add(new MySagaState());

                // Asert
                Assert.That(fixture.Data.Count(), Is.EqualTo(1));
                Assert.That(fixture.Data.Single().Id, Is.Not.Null);
            }
        }
예제 #22
0
    public void CanSetUpFakeSagaData()
    {
        using var fixture = SagaFixture.For <MySaga>();

        fixture.Add(new MySagaState {
            Text = "I know you!"
        });
        fixture.AddRange(new[] { new MySagaState {
                                     Text = "I know you too!"
                                 } });

        Assert.That(fixture.Data.Count(), Is.EqualTo(2));
        Assert.That(fixture.Data.OfType <MySagaState>().Count(d => d.Text == "I know you!"), Is.EqualTo(1));
        Assert.That(fixture.Data.OfType <MySagaState>().Count(d => d.Text == "I know you too!"), Is.EqualTo(1));
    }
예제 #23
0
        public void The_Systems_Track_The_Ola_For_Customer_Onboarding()
        {
            var customerName = RandomName;
            var bus          = new FakeBus();

            using (var fixture = SagaFixture.For(() => new OnboardCustomerSaga(bus)))
            {
                fixture.Deliver(new OnboardCustomer {
                    CustomerName = customerName
                });
                bus.HasDeferredLocal <VerifyCustomerOnboardingOla>(
                    with: x => x.CustomerName == customerName,
                    because: "it should start tracking the OLA");
            }
        }
예제 #24
0
        public void SagaDataWithNonEmptyIdIsAddedToSagaFixtureData()
        {
            using (var fixture = SagaFixture.For <MySaga>())
            {
                // Arrange

                // Act
                fixture.Add(new MySagaState {
                    Id = Guid.NewGuid()
                });

                // Assert
                Assert.That(fixture.Data.Count(), Is.EqualTo(1));
            }
        }
예제 #25
0
    public void CanDispatchFailedMessage()
    {
        var failedMessageWasReceived = new ManualResetEvent(false);

        Using(failedMessageWasReceived);

        using var fixture = SagaFixture.For(() => new MySaga(failedMessageWasReceived), secondLevelRetriesEnabled: true);

        fixture.DumpLogsOnDispose();
        fixture.Add(new MySagaState {
            Text = "known-string"
        });
        fixture.DeliverFailed(new TestMessage("known-string"), new DriveNotFoundException("B:"));
        failedMessageWasReceived.WaitOrDie(TimeSpan.FromSeconds(3));
    }
    public async Task YeahItWorks()
    {
        var receivedEvents = new ConcurrentQueue <string>();

        using var fixture = SagaFixture.For(() => new RandomSaga(receivedEvents));

        fixture.Deliver(new RandomMessage("hej"));
        fixture.HandlerExceptions.ThrowIfNotEmpty();

        await Task.Delay(millisecondsDelay : 17);

        fixture.Deliver(new RandomMessage("hej igen"));

        Assert.That(receivedEvents.Count, Is.EqualTo(2));
        Assert.That(receivedEvents, Is.EqualTo(new[] { "hej", "hej igen" }));
    }
예제 #27
0
        public void CanGetCaughtException()
        {
            using (var fixture = SagaFixture.For <MySaga>())
            {
                fixture.Deliver(new FailingTestMessage("whoohoo"));

                var handlerExceptions = fixture.HandlerExceptions.ToList();

                Console.WriteLine(string.Join(Environment.NewLine + Environment.NewLine, handlerExceptions));

                Assert.That(handlerExceptions.Count, Is.EqualTo(1));

                var exception = handlerExceptions.Single();

                Assert.That(exception.Exception, Is.TypeOf <RebusApplicationException>());
                Assert.That(exception.Exception.ToString(), Contains.Substring("oh no something bad happened"));
            }
        }
예제 #28
0
        public void GetsHumanReadableExceptionWhenSomethingGoesWrong()
        {
            // arrange
            var data = new List <SomeSagaData> {
                new SomeSagaData {
                    SagaDataId = 23
                }
            };
            var fixture = new SagaFixture <SomeSagaData>(new SomeSaga(), data);

            // act
            var exception = Assert.Throws <ApplicationException>(() => fixture.Handle(new SomePoisonMessage {
                SagaDataId = 23
            }));

            Console.WriteLine(exception.ToString());

            // assert
            exception.Message.ShouldContain("Oh no, something bad happened while processing message with saga data id 23");
        }
        public void ThrowsProperExceptionWhenAttemptingToEstablishMessageContextWithItemsDictionary()
        {
            var saga        = new SearchSaga();
            var fixture     = new SagaFixture <SearchSagaData>(saga);
            var fakeContext = MockRepository.GenerateMock <IMessageContext>();

            fakeContext.Stub(s => s.ReturnAddress).Return("queuename");
            fakeContext.Stub(s => s.Headers).Return(new Dictionary <string, object>());

            // act
            var ex = Assert
                     .Throws <ArgumentException>(() =>
            {
                using (FakeMessageContext.Establish(fakeContext))
                {
                    fixture.Handle("w00000t!");
                }
            });

            ex.Message.ShouldContain("has null as the Items property");
        }
예제 #30
0
        public void If_The_Ola_Is_Breached_Then_And_No_Sales_Call_Was_Placed_Then_No_Cancellation_Takes_Place()
        {
            var customerName = RandomName;
            var bus          = new FakeBus();

            using (var fixture = SagaFixture.For(() => new OnboardCustomerSaga(bus)))
            {
                fixture.Deliver(new OnboardCustomer {
                    CustomerName = customerName
                });
                bus.HasNotSentLocal <ScheduleASalesCall>(
                    because: "the account creation is has not been confirmed");

                fixture.Deliver(new VerifyCustomerOnboardingOla {
                    CustomerName = customerName
                });

                fixture.ShouldHaveCompleted();
                bus.HasNotSentLocal <CancellSalesCall>(
                    because: "the  sales call is only cancelled after an OLA breach if it has already been requested");
            }
        }