public void SendAllAtOnce_Data()
        {
            var messageList = new List <SmsData> {
                new SmsData("9384938", "3943lasdkf;j"), new SmsData("99999", "dj;alsdfkj")
            };
            var sendTimeUtc           = DateTime.Now;
            var sendAllMessagesAtOnce = new SendAllMessagesAtOnce {
                Messages = messageList, SendTimeUtc = sendTimeUtc, UserOlsenTimeZone = "timeZone", CoordinatorId = Guid.NewGuid(), MetaData = new SmsMetaData()
            };

            var ravenScheduleDocuments = MockRepository.GenerateStrictMock <IRavenScheduleDocuments>();
            var sendingMessages        = new List <ScheduleSmsForSendingLater>();

            ravenScheduleDocuments.Expect(r => r.SaveSchedules(Arg <List <ScheduleSmsForSendingLater> > .Is.NotNull, Arg <Guid> .Is.Equal(sendAllMessagesAtOnce.CoordinatorId)))
            .WhenCalled(r => sendingMessages = (List <ScheduleSmsForSendingLater>)r.Arguments[0]);
            ravenScheduleDocuments.Expect(r => r.SaveCoordinator(Arg <CoordinatorCreated> .Is.Anything));

            var timingManager = MockRepository.GenerateMock <ICalculateSmsTiming>();

            var sagaData = new CoordinateSmsSchedulingData {
                Originator = "originator", Id = Guid.NewGuid()
            };

            Test.Initialize();
            Test.Saga <CoordinateSmsScheduler>()
            .WithExternalDependencies(s =>
            {
                s.TimingManager          = timingManager;
                s.Data                   = sagaData;
                s.RavenScheduleDocuments = ravenScheduleDocuments;
            })
            .ExpectSend <ScheduleSmsForSendingLater>(l =>
                                                     l.SendMessageAtUtc == sendTimeUtc &&
                                                     l.SmsData.Message == sendAllMessagesAtOnce.Messages[0].Message &&
                                                     l.SmsData.Mobile == sendAllMessagesAtOnce.Messages[0].Mobile &&
                                                     l.SmsMetaData == sendAllMessagesAtOnce.MetaData)
            .ExpectSend <ScheduleSmsForSendingLater>(l =>
                                                     l.SendMessageAtUtc == sendTimeUtc &&
                                                     l.SmsData.Message == sendAllMessagesAtOnce.Messages[1].Message &&
                                                     l.SmsData.Mobile == sendAllMessagesAtOnce.Messages[1].Mobile &&
                                                     l.SmsMetaData == sendAllMessagesAtOnce.MetaData)
            .ExpectPublish <CoordinatorCreated>(c =>
                                                c.CoordinatorId == sendAllMessagesAtOnce.CoordinatorId &&
                                                c.ScheduledMessages.Count == 2 &&
                                                c.ScheduledMessages[0].Number == sendAllMessagesAtOnce.Messages[0].Mobile &&
                                                c.ScheduledMessages[0].ScheduleMessageId == sendingMessages[0].ScheduleMessageId &&
                                                c.ScheduledMessages[0].ScheduleMessageId != Guid.Empty &&
                                                c.ScheduledMessages[0].ScheduledTimeUtc == sendTimeUtc &&

                                                c.ScheduledMessages[1].Number == sendAllMessagesAtOnce.Messages[1].Mobile &&
                                                c.ScheduledMessages[1].ScheduleMessageId == sendingMessages[1].ScheduleMessageId &&
                                                c.ScheduledMessages[1].ScheduleMessageId != Guid.Empty &&
                                                c.ScheduledMessages[1].ScheduledTimeUtc == sendTimeUtc &&
                                                c.UserOlsenTimeZone == sendAllMessagesAtOnce.UserOlsenTimeZone)
            .ExpectTimeoutToBeSetAt <CoordinatorTimeout>((state, timeout) => timeout == sendAllMessagesAtOnce.SendTimeUtc.AddMinutes(2))
            .When(s => s.Handle(sendAllMessagesAtOnce));

            Assert.That(sendingMessages.Count, Is.EqualTo(2));
            timingManager.VerifyAllExpectations();
        }
        public void TrickleThreeMessagesOverTenMinutesOneMessageFailsCoordinatorStillCompletes()
        {
            var coordinatorId          = Guid.NewGuid();
            var ravenScheduleDocuments = MockRepository.GenerateStrictMock <IRavenScheduleDocuments>();

            ravenScheduleDocuments.Expect(r => r.SaveCoordinator(Arg <CoordinatorCreated> .Is.Anything));
            ravenScheduleDocuments.Expect(r => r.SaveSchedules(Arg <List <ScheduleSmsForSendingLater> > .Is.Anything, Arg <Guid> .Is.Anything));
            ravenScheduleDocuments.Expect(r => r.AreCoordinatedSchedulesComplete(coordinatorId)).Return(true);
            ravenScheduleDocuments.Expect(r => r.MarkCoordinatorAsComplete(Arg <Guid> .Is.Equal(coordinatorId), Arg <DateTime> .Is.Anything));
            ravenScheduleDocuments.Expect(r => r.GetScheduleSummary(coordinatorId)).Return(new List <ScheduledMessagesStatusCountInCoordinatorIndex.ReduceResult>());
            var startTime = DateTime.Now.AddHours(3);
            var duration  = new TimeSpan(0, 10, 0);
            var trickleMultipleMessages = new TrickleSmsOverCalculatedIntervalsBetweenSetDates
            {
                StartTimeUtc = startTime,
                Messages     = new List <SmsData>
                {
                    new SmsData("mobile#1", "message"),
                    new SmsData("mobile#2", "message2"),
                    new SmsData("mobile#3", "message3")
                },
                Duration      = duration,
                CoordinatorId = coordinatorId,
                MetaData      = new SmsMetaData()
            };

            var timingManager = MockRepository.GenerateMock <ICalculateSmsTiming>();
            var messageTiming = new List <DateTime> {
                startTime, startTime.AddMinutes(5), startTime.AddMinutes(10)
            };

            timingManager.Expect(t => t.CalculateTiming(startTime, duration, 3))
            .Return(messageTiming);

            var sagaData = new CoordinateSmsSchedulingData {
                Id = Guid.NewGuid(), Originator = "o", OriginalMessageId = "i"
            };

            Test.Initialize();
            Test.Saga <CoordinateSmsScheduler>()
            .WithExternalDependencies(s =>
            {
                s.TimingManager          = timingManager;
                s.Data                   = sagaData;
                s.RavenScheduleDocuments = ravenScheduleDocuments;
            })
            .ExpectSend <ScheduleSmsForSendingLater>(l => l.SmsData.Mobile == trickleMultipleMessages.Messages[0].Mobile)
            .ExpectSend <ScheduleSmsForSendingLater>(l => l.SmsData.Mobile == trickleMultipleMessages.Messages[1].Mobile)
            .ExpectSend <ScheduleSmsForSendingLater>(l => l.SmsData.Mobile == trickleMultipleMessages.Messages[2].Mobile)
            .ExpectPublish <CoordinatorCreated>()
            .ExpectTimeoutToBeSetAt <CoordinatorTimeout>((state, timeout) => true)
            .When(s => s.Handle(trickleMultipleMessages))
            .AssertSagaCompletionIs(false)
            .ExpectPublish <CoordinatorCompleted>()
            .When(s => s.Timeout(new CoordinatorTimeout()))
            .AssertSagaCompletionIs(true);

            timingManager.VerifyAllExpectations();
        }
        public void TrickleThreeMessagesFirstSentPausedThenResumedOutOfOrder()
        {
            var startTime              = DateTime.Now.AddHours(3);
            var duration               = new TimeSpan(0, 10, 0);
            var coordinatorId          = Guid.NewGuid();
            var ravenScheduleDocuments = MockRepository.GenerateStrictMock <IRavenScheduleDocuments>();

            ravenScheduleDocuments.Expect(r => r.SaveSchedules(Arg <List <ScheduleSmsForSendingLater> > .Is.Anything, Arg <Guid> .Is.Anything));
            ravenScheduleDocuments.Expect(r => r.SaveCoordinator(Arg <CoordinatorCreated> .Is.Anything));
            ravenScheduleDocuments.Expect(r => r.GetActiveScheduleTrackingData(coordinatorId)).Return(new List <ScheduleTrackingData> {
                new ScheduleTrackingData(), new ScheduleTrackingData()
            });
            ravenScheduleDocuments.Expect(r => r.AreCoordinatedSchedulesComplete(coordinatorId)).Return(true);
            ravenScheduleDocuments.Expect(r => r.MarkCoordinatorAsComplete(Arg <Guid> .Is.Equal(coordinatorId), Arg <DateTime> .Is.Anything));
            ravenScheduleDocuments.Expect(r => r.GetScheduleSummary(coordinatorId)).Return(new List <ScheduledMessagesStatusCountInCoordinatorIndex.ReduceResult>());
            var trickleMultipleMessages = new TrickleSmsOverCalculatedIntervalsBetweenSetDates
            {
                StartTimeUtc = startTime,
                Messages     = new List <SmsData>
                {
                    new SmsData("mobile#1", "message"),
                    new SmsData("mobile#2", "message2"),
                    new SmsData("mobile#3", "message3")
                },
                Duration      = duration,
                CoordinatorId = coordinatorId,
                MetaData      = new SmsMetaData()
            };

            var sagaData = new CoordinateSmsSchedulingData {
                Id = Guid.NewGuid(), Originator = "o", OriginalMessageId = "i"
            };

            Test.Initialize();
            Test.Saga <CoordinateSmsScheduler>()
            .WithExternalDependencies(d => { d.Data = sagaData; d.RavenScheduleDocuments = ravenScheduleDocuments; d.TimingManager = new CalculateSmsTiming(); })
            .ExpectSend <ScheduleSmsForSendingLater>(l => l.SmsData.Mobile == trickleMultipleMessages.Messages[0].Mobile)
            .ExpectSend <ScheduleSmsForSendingLater>(l => l.SmsData.Mobile == trickleMultipleMessages.Messages[1].Mobile)
            .ExpectSend <ScheduleSmsForSendingLater>(l => l.SmsData.Mobile == trickleMultipleMessages.Messages[2].Mobile)
            .ExpectTimeoutToBeSetAt <CoordinatorTimeout>((state, timeout) => true)
            .When(s => s.Handle(trickleMultipleMessages))
            .ExpectSend <ResumeScheduledMessageWithOffset>()
            .ExpectSend <ResumeScheduledMessageWithOffset>()
            .When(s => s.Handle(new ResumeTrickledMessages {
                MessageRequestTimeUtc = DateTime.Now.AddMinutes(-10)
            }))
            .ExpectNotSend <PauseScheduledMessageIndefinitely>(a => true)
            .ExpectNotSend <PauseScheduledMessageIndefinitely>(a => true)
            .When(s => s.Handle(new PauseTrickledMessagesIndefinitely {
                MessageRequestTimeUtc = DateTime.Now.AddMinutes(-11)
            }))
            .AssertSagaCompletionIs(false)
            .ExpectPublish <CoordinatorCompleted>()
            .When(s => s.Timeout(new CoordinatorTimeout()))
            .AssertSagaCompletionIs(true);
        }
        public void TrickleMessagesOverPeriod_Data()
        {
            var messageList = new List<SmsData> { new SmsData("9384938", "3943lasdkf;j"), new SmsData("99999", "dj;alsdfkj")};
            var trickleMessagesOverTime = new TrickleSmsOverCalculatedIntervalsBetweenSetDates { Duration = new TimeSpan(1000), Messages = messageList, StartTimeUtc = DateTime.Now };

            var timingManager = MockRepository.GenerateMock<ICalculateSmsTiming>();

            var datetimeSpacing = new List<DateTime> { DateTime.Now.AddMinutes(10), DateTime.Now.AddMinutes(20) };
            timingManager
                .Expect(t => t.CalculateTiming(trickleMessagesOverTime.StartTimeUtc, trickleMessagesOverTime.Duration, trickleMessagesOverTime.Messages.Count))
                .Return(datetimeSpacing);

            var sagaData = new CoordinateSmsSchedulingData { Originator = "originator", Id = Guid.NewGuid() };
            Test.Initialize();
            Test.Saga<CoordinateSmsScheduler>()
                .WithExternalDependencies(s =>
                {
                    s.TimingManager = timingManager;
                    s.Data = sagaData;
                })
                    .ExpectSend<ScheduleSmsForSendingLater>(l =>
                        l.SendMessageAtUtc == datetimeSpacing[0].ToUniversalTime() &&
                        l.SmsData.Message == trickleMessagesOverTime.Messages[0].Message &&
                        l.SmsData.Mobile == trickleMessagesOverTime.Messages[0].Mobile &&
                        l.SmsMetaData == trickleMessagesOverTime.MetaData)
                    .ExpectSend<ScheduleSmsForSendingLater>(l =>
                        l.SendMessageAtUtc == datetimeSpacing[1].ToUniversalTime() &&
                        l.SmsData.Message == trickleMessagesOverTime.Messages[1].Message &&
                        l.SmsData.Mobile == trickleMessagesOverTime.Messages[1].Mobile &&
                        l.SmsMetaData == trickleMessagesOverTime.MetaData)
                    .ExpectPublish<CoordinatorCreated>(c =>
                        c.CoordinatorId == sagaData.Id &&
                        c.ScheduledMessages.Count == 2 &&
                        c.ScheduledMessages[0].Number == trickleMessagesOverTime.Messages[0].Mobile &&
                        c.ScheduledMessages[0].ScheduleMessageId == sagaData.ScheduledMessageStatus[0].ScheduledSms.ScheduleMessageId &&
                        c.ScheduledMessages[0].ScheduleMessageId != Guid.Empty &&
                        c.ScheduledMessages[0].ScheduledTimeUtc == datetimeSpacing[0].ToUniversalTime() &&

                        c.ScheduledMessages[1].Number == trickleMessagesOverTime.Messages[1].Mobile &&
                        c.ScheduledMessages[1].ScheduleMessageId == sagaData.ScheduledMessageStatus[1].ScheduledSms.ScheduleMessageId &&
                        c.ScheduledMessages[1].ScheduleMessageId != Guid.Empty &&
                        c.ScheduledMessages[1].ScheduledTimeUtc == datetimeSpacing[1].ToUniversalTime())
                .When(s => s.Handle(trickleMessagesOverTime));

            Assert.That(sagaData.MessagesScheduled, Is.EqualTo(2));
            Assert.That(sagaData.ScheduledMessageStatus[0].MessageStatus, Is.EqualTo(MessageStatus.WaitingForScheduling));
            Assert.That(sagaData.ScheduledMessageStatus[1].MessageStatus, Is.EqualTo(MessageStatus.WaitingForScheduling));
            timingManager.VerifyAllExpectations();
        }
        public void TrickleMessagesMessagesPausedConfirmedButAlreadySentThrowsException_Data()
        {
            var messageList = new SmsData("99999", "dj;alsdfkj");

            var scheduleId = Guid.NewGuid();
            var messageSchedulePaused = new MessageSchedulePaused { ScheduleId = scheduleId };

            var scheduledMessageStatuses = new List<ScheduledMessageStatus>
            {
                new ScheduledMessageStatus(new ScheduleSmsForSendingLater { SmsData = messageList, ScheduleMessageId = scheduleId }, MessageStatus.Sent)
            };

            var sagaData = new CoordinateSmsSchedulingData { ScheduledMessageStatus = scheduledMessageStatuses, Id = Guid.NewGuid(), Originator = "o", OriginalMessageId = "i" };

            var coordinateSmsScheduler = new CoordinateSmsScheduler {Data = sagaData};
            Assert.That(() => coordinateSmsScheduler.Handle(messageSchedulePaused), Throws.Exception.With.Message.EqualTo("Scheduled message " + scheduleId + " is already sent."));
        }
        public void TrickleMessagesResumeMessageSending_Data()
        {
            var ravenScheduleDocuments = MockRepository.GenerateMock <IRavenScheduleDocuments>();

            var timingManager = MockRepository.GenerateMock <ICalculateSmsTiming>();
            var dateTime      = DateTime.Now;
            var sagaId        = Guid.NewGuid();
            var sagaData      = new CoordinateSmsSchedulingData {
                Originator = "o", OriginalScheduleStartTime = dateTime.AddMinutes(-5), CoordinatorId = sagaId
            };
            var pausedTrackedMessages = new List <ScheduleTrackingData>
            {
                new ScheduleTrackingData {
                    MessageStatus = MessageStatus.Paused, ScheduleId = Guid.NewGuid()
                },
                new ScheduleTrackingData {
                    MessageStatus = MessageStatus.Paused, ScheduleId = Guid.NewGuid()
                }
            };

            ravenScheduleDocuments.Expect(r => r.GetActiveScheduleTrackingData(sagaId)).Return(pausedTrackedMessages);

            var resumeTricklesMessages = new ResumeTrickledMessages {
                ResumeTimeUtc = dateTime
            };

            Test.Initialize();
            Test.Saga <CoordinateSmsScheduler>()
            .WithExternalDependencies(s =>
            {
                s.TimingManager          = timingManager;
                s.Data                   = sagaData;
                s.RavenScheduleDocuments = ravenScheduleDocuments;
            })
            .ExpectSend <ResumeScheduledMessageWithOffset>(
                l =>
                l.ScheduleMessageId == pausedTrackedMessages[0].ScheduleId &&
                l.Offset == new TimeSpan(0, 0, 5, 0))
            .ExpectSend <ResumeScheduledMessageWithOffset>(
                l =>
                l.ScheduleMessageId == pausedTrackedMessages[1].ScheduleId &&
                l.Offset == new TimeSpan(0, 0, 5, 0))
            .When(s => s.Handle(resumeTricklesMessages));

            timingManager.VerifyAllExpectations();
        }
        public void TrickleMessagesRescheduleMessageSending_Data()
        {
            var ravenScheduleDocuments = MockRepository.GenerateMock <IRavenScheduleDocuments>();

            var dateTime   = DateTime.Now;
            var finishTime = dateTime.AddMinutes(9);
            var sagaId     = Guid.NewGuid();
            var sagaData   = new CoordinateSmsSchedulingData {
                Originator = "o", OriginalScheduleStartTime = dateTime.AddMinutes(-5), CoordinatorId = sagaId
            };
            var pausedTrackedMessages = new List <ScheduleTrackingData>
            {
                new ScheduleTrackingData {
                    MessageStatus = MessageStatus.Paused, ScheduleId = Guid.NewGuid()
                },
                new ScheduleTrackingData {
                    MessageStatus = MessageStatus.Paused, ScheduleId = Guid.NewGuid()
                }
            };

            ravenScheduleDocuments.Expect(r => r.GetActiveScheduleTrackingData(sagaId)).Return(pausedTrackedMessages);

            var rescheduleTrickledMessages = new RescheduleTrickledMessages {
                ResumeTimeUtc = dateTime, FinishTimeUtc = finishTime
            };

            Test.Initialize();
            Test.Saga <CoordinateSmsScheduler>()
            .WithExternalDependencies(s =>
            {
                s.Data = sagaData; s.RavenScheduleDocuments = ravenScheduleDocuments;
            })
            .ExpectSend <RescheduleScheduledMessageWithNewTime>(
                l =>
                l.ScheduleMessageId == pausedTrackedMessages[0].ScheduleId &&
                l.NewScheduleTimeUtc.Equals(dateTime))
            .ExpectSend <RescheduleScheduledMessageWithNewTime>(
                l =>
                l.ScheduleMessageId == pausedTrackedMessages[1].ScheduleId &&
                l.NewScheduleTimeUtc.Equals(finishTime))
            .When(s => s.Handle(rescheduleTrickledMessages));
        }
        public void CoordinatorTimeoutMessagesNotYetAllSentRequestsAnotherTimeoutUsingMaxExpectedScheduleDate()
        {
            var ravenScheduleDocuments = MockRepository.GenerateMock<IRavenScheduleDocuments>();
            var coordinatorId = Guid.NewGuid();
            var sagaData = new CoordinateSmsSchedulingData { Originator = "o", CoordinatorId = coordinatorId };

            var maxScheduleDateTime = DateTime.Now.AddMinutes(5);
            ravenScheduleDocuments.Expect(r => r.AreCoordinatedSchedulesComplete(coordinatorId)).Return(false);
            ravenScheduleDocuments.Expect(r => r.GetMaxScheduleDateTime(coordinatorId)).Return(maxScheduleDateTime);

            Test.Initialize();
            Test.Saga<CoordinateSmsScheduler>()
                .WithExternalDependencies(s =>
                {
                    s.Data = sagaData; s.RavenScheduleDocuments = ravenScheduleDocuments;
                })
                    .ExpectTimeoutToBeSetAt<CoordinatorTimeout>((state, timeout) => timeout == maxScheduleDateTime.AddMinutes(2))
                .When(s => s.Timeout(new CoordinatorTimeout()))
                .AssertSagaCompletionIs(false);
        }
        public void CoordinatorTimeoutMessagesAllSentSagaCompletes()
        {
            var ravenScheduleDocuments = MockRepository.GenerateMock<IRavenScheduleDocuments>();
            var coordinatorId = Guid.NewGuid();
            var sagaData = new CoordinateSmsSchedulingData { Originator = "o", CoordinatorId = coordinatorId };

            ravenScheduleDocuments.Expect(r => r.AreCoordinatedSchedulesComplete(coordinatorId)).Return(true);
            ravenScheduleDocuments.Expect(r => r.GetScheduleSummary(coordinatorId)).Return(new List<ScheduledMessagesStatusCountInCoordinatorIndex.ReduceResult>());

            Test.Initialize();
            Test.Saga<CoordinateSmsScheduler>()
                .WithExternalDependencies(s =>
                {
                    s.Data = sagaData; s.RavenScheduleDocuments = ravenScheduleDocuments;
                })
                    .ExpectPublish<CoordinatorCompleted>()
                    .ExpectSendLocal<CoordinatorCompleteEmailWithSummary>()
                .When(s => s.Timeout(new CoordinatorTimeout()))
                .AssertSagaCompletionIs(true);
        }
        public void CoordinatorTimeoutMessagesNotYetAllSentRequestsAnotherTimeoutFor2MinutesAsMaxExpectedScheduleDateHasPassed()
        {
            var ravenScheduleDocuments = MockRepository.GenerateMock<IRavenScheduleDocuments>();
            var coordinatorId = Guid.NewGuid();
            var sagaData = new CoordinateSmsSchedulingData { Originator = "o", CoordinatorId = coordinatorId };

            var maxScheduleDateTime = DateTime.Now.AddMinutes(-1);
            ravenScheduleDocuments.Expect(r => r.AreCoordinatedSchedulesComplete(coordinatorId)).Return(false);
            ravenScheduleDocuments.Expect(r => r.GetMaxScheduleDateTime(coordinatorId)).Return(maxScheduleDateTime);

            Test.Initialize();
            Test.Saga<CoordinateSmsScheduler>()
                .WithExternalDependencies(s =>
                {
                    s.Data = sagaData; s.RavenScheduleDocuments = ravenScheduleDocuments;
                })
                // NOTE: Test is super brittle because of DateTime.Now - ideally this would be mocked
                    .ExpectTimeoutToBeSetAt<CoordinatorTimeout>((state, timeout) => timeout > DateTime.UtcNow.AddMinutes(1) && timeout < DateTime.UtcNow.AddMinutes(2))
                .When(s => s.Timeout(new CoordinatorTimeout()))
                .AssertSagaCompletionIs(false);
        }
        public void CoordinatorTimeoutMessagesAllSentSagaCompletes()
        {
            var ravenScheduleDocuments = MockRepository.GenerateMock <IRavenScheduleDocuments>();
            var coordinatorId          = Guid.NewGuid();
            var sagaData = new CoordinateSmsSchedulingData {
                Originator = "o", CoordinatorId = coordinatorId
            };

            ravenScheduleDocuments.Expect(r => r.AreCoordinatedSchedulesComplete(coordinatorId)).Return(true);
            ravenScheduleDocuments.Expect(r => r.GetScheduleSummary(coordinatorId)).Return(new List <ScheduledMessagesStatusCountInCoordinatorIndex.ReduceResult>());

            Test.Initialize();
            Test.Saga <CoordinateSmsScheduler>()
            .WithExternalDependencies(s =>
            {
                s.Data = sagaData; s.RavenScheduleDocuments = ravenScheduleDocuments;
            })
            .ExpectPublish <CoordinatorCompleted>()
            .ExpectSendLocal <CoordinatorCompleteEmailWithSummary>()
            .When(s => s.Timeout(new CoordinatorTimeout()))
            .AssertSagaCompletionIs(true);
        }
        public void TrickleMessagesPauseMessagesIndefinitely_Data()
        {
            var ravenScheduleDocuments = MockRepository.GenerateMock <IRavenScheduleDocuments>();

            var pauseMessageSending = new PauseTrickledMessagesIndefinitely();

            var timingManager = MockRepository.GenerateMock <ICalculateSmsTiming>();

            var sagaId   = Guid.NewGuid();
            var sagaData = new CoordinateSmsSchedulingData {
                Id = Guid.NewGuid(), Originator = "o", OriginalMessageId = "i", CoordinatorId = sagaId
            };
            var pausedTrackedMessages = new List <ScheduleTrackingData>
            {
                new ScheduleTrackingData {
                    MessageStatus = MessageStatus.Scheduled, ScheduleId = Guid.NewGuid()
                },
                new ScheduleTrackingData {
                    MessageStatus = MessageStatus.Scheduled, ScheduleId = Guid.NewGuid()
                }
            };

            ravenScheduleDocuments.Expect(r => r.GetActiveScheduleTrackingData(sagaId)).Return(pausedTrackedMessages);

            Test.Initialize();
            Test.Saga <CoordinateSmsScheduler>()
            .WithExternalDependencies(s =>
            {
                s.TimingManager          = timingManager;
                s.Data                   = sagaData;
                s.RavenScheduleDocuments = ravenScheduleDocuments;
            })
            .ExpectSend <PauseScheduledMessageIndefinitely>(l => l.ScheduleMessageId == pausedTrackedMessages[0].ScheduleId)
            .ExpectSend <PauseScheduledMessageIndefinitely>(l => l.ScheduleMessageId == pausedTrackedMessages[1].ScheduleId)
            .When(s => s.Handle(pauseMessageSending));

            timingManager.VerifyAllExpectations();
        }
        public void CoordinatorTimeoutMessagesNotYetAllSentRequestsAnotherTimeoutUsingMaxExpectedScheduleDate()
        {
            var ravenScheduleDocuments = MockRepository.GenerateMock <IRavenScheduleDocuments>();
            var coordinatorId          = Guid.NewGuid();
            var sagaData = new CoordinateSmsSchedulingData {
                Originator = "o", CoordinatorId = coordinatorId
            };

            var maxScheduleDateTime = DateTime.Now.AddMinutes(5);

            ravenScheduleDocuments.Expect(r => r.AreCoordinatedSchedulesComplete(coordinatorId)).Return(false);
            ravenScheduleDocuments.Expect(r => r.GetMaxScheduleDateTime(coordinatorId)).Return(maxScheduleDateTime);

            Test.Initialize();
            Test.Saga <CoordinateSmsScheduler>()
            .WithExternalDependencies(s =>
            {
                s.Data = sagaData; s.RavenScheduleDocuments = ravenScheduleDocuments;
            })
            .ExpectTimeoutToBeSetAt <CoordinatorTimeout>((state, timeout) => timeout == maxScheduleDateTime.AddMinutes(2))
            .When(s => s.Timeout(new CoordinatorTimeout()))
            .AssertSagaCompletionIs(false);
        }
        public void CoordinatorTimeoutMessagesNotYetAllSentRequestsAnotherTimeoutFor2MinutesAsMaxExpectedScheduleDateHasPassed()
        {
            var ravenScheduleDocuments = MockRepository.GenerateMock <IRavenScheduleDocuments>();
            var coordinatorId          = Guid.NewGuid();
            var sagaData = new CoordinateSmsSchedulingData {
                Originator = "o", CoordinatorId = coordinatorId
            };

            var maxScheduleDateTime = DateTime.Now.AddMinutes(-1);

            ravenScheduleDocuments.Expect(r => r.AreCoordinatedSchedulesComplete(coordinatorId)).Return(false);
            ravenScheduleDocuments.Expect(r => r.GetMaxScheduleDateTime(coordinatorId)).Return(maxScheduleDateTime);

            Test.Initialize();
            Test.Saga <CoordinateSmsScheduler>()
            .WithExternalDependencies(s =>
            {
                s.Data = sagaData; s.RavenScheduleDocuments = ravenScheduleDocuments;
            })
            // NOTE: Test is super brittle because of DateTime.Now - ideally this would be mocked
            .ExpectTimeoutToBeSetAt <CoordinatorTimeout>((state, timeout) => timeout > DateTime.UtcNow.AddMinutes(1) && timeout < DateTime.UtcNow.AddMinutes(2))
            .When(s => s.Timeout(new CoordinatorTimeout()))
            .AssertSagaCompletionIs(false);
        }
        public void TrickleThreeMessagesSpacedAMinuteApartPausedAfterFirstThenResumed()
        {
            var startTime = DateTime.Now.AddHours(3);
            var timeSpacing = new TimeSpan(0, 10, 0);
            var trickleMultipleMessages = new TrickleSmsWithDefinedTimeBetweenEachMessage
            {
                StartTimeUtc = startTime,
                Messages = new List<SmsData>
                {
                    new SmsData("mobile#1", "message"),
                    new SmsData("mobile#2", "message2"),
                    new SmsData("mobile#3", "message3")
                },
                TimeSpacing = timeSpacing
            };

            var sagaData = new CoordinateSmsSchedulingData { Id = Guid.NewGuid(), Originator = "o", OriginalMessageId = "i" };
            Test.Initialize();
            Test.Saga<CoordinateSmsScheduler>()
                .WithExternalDependencies(d => d.Data = sagaData)
                    .ExpectSend<ScheduleSmsForSendingLater>(l => l.SmsData.Mobile == trickleMultipleMessages.Messages[0].Mobile)
                    .ExpectSend<ScheduleSmsForSendingLater>(l => l.SmsData.Mobile == trickleMultipleMessages.Messages[1].Mobile)
                    .ExpectSend<ScheduleSmsForSendingLater>(l => l.SmsData.Mobile == trickleMultipleMessages.Messages[2].Mobile)
                .When(s => s.Handle(trickleMultipleMessages))
                .When(s => s.Handle(new ScheduledSmsSent { ConfirmationData = new SmsConfirmationData("r", DateTime.Now, 1m), ScheduledSmsId = sagaData.ScheduledMessageStatus[0].ScheduledSms.ScheduleMessageId }))
                    .ExpectSend<PauseScheduledMessageIndefinitely>()
                    .ExpectSend<PauseScheduledMessageIndefinitely>()
                .When(s => s.Handle(new PauseTrickledMessagesIndefinitely()))
                .When(s => s.Handle(new MessageSchedulePaused { ScheduleId = sagaData.ScheduledMessageStatus[1].ScheduledSms.ScheduleMessageId }))
                .When(s => s.Handle(new MessageSchedulePaused { ScheduleId = sagaData.ScheduledMessageStatus[2].ScheduledSms.ScheduleMessageId }))
                    .ExpectSend<ResumeScheduledMessageWithOffset>()
                    .ExpectSend<ResumeScheduledMessageWithOffset>()
                .When(s => s.Handle(new ResumeTrickledMessages()))
                .When(s => s.Handle(new ScheduledSmsSent { ConfirmationData = new SmsConfirmationData("r", DateTime.Now, 1m), ScheduledSmsId = sagaData.ScheduledMessageStatus[1].ScheduledSms.ScheduleMessageId }))
                    .AssertSagaCompletionIs(false)
                    .ExpectPublish<CoordinatorCompleted>()
                .When(s => s.Handle(new ScheduledSmsSent { ConfirmationData = new SmsConfirmationData("r", DateTime.Now, 1m), ScheduledSmsId = sagaData.ScheduledMessageStatus[2].ScheduledSms.ScheduleMessageId }))
                    .AssertSagaCompletionIs(true);

            Assert.That(sagaData.MessagesScheduled, Is.EqualTo(3));
            Assert.That(sagaData.MessagesConfirmedSentOrFailed, Is.EqualTo(3));
        }
        public void TrickleThreeMessagesOverTenMinutesOneMessageFailsCoordinatorStillCompletes()
        {
            var startTime = DateTime.Now.AddHours(3);
            var duration = new TimeSpan(0, 10, 0);
            var trickleMultipleMessages = new TrickleSmsOverCalculatedIntervalsBetweenSetDates
            {
                StartTimeUtc = startTime,
                Messages = new List<SmsData>
                {
                    new SmsData("mobile#1", "message"),
                    new SmsData("mobile#2", "message2"),
                    new SmsData("mobile#3", "message3")
                },
                Duration = duration
            };

            var timingManager = MockRepository.GenerateMock<ICalculateSmsTiming>();
            var messageTiming = new List<DateTime> { startTime, startTime.AddMinutes(5), startTime.AddMinutes(10) };
            timingManager.Expect(t => t.CalculateTiming(startTime, duration, 3))
                .Return(messageTiming);

            var sagaData = new CoordinateSmsSchedulingData { Id = Guid.NewGuid(), Originator = "o", OriginalMessageId = "i" };
            Test.Initialize();
            Test.Saga<CoordinateSmsScheduler>()
                .WithExternalDependencies(s =>
                    {
                        s.TimingManager = timingManager;
                        s.Data = sagaData;
                    })
                    .ExpectSend<ScheduleSmsForSendingLater>(l => l.SmsData.Mobile == trickleMultipleMessages.Messages[0].Mobile)
                    .ExpectSend<ScheduleSmsForSendingLater>(l => l.SmsData.Mobile == trickleMultipleMessages.Messages[1].Mobile)
                    .ExpectSend<ScheduleSmsForSendingLater>(l => l.SmsData.Mobile == trickleMultipleMessages.Messages[2].Mobile)
                    .ExpectPublish<CoordinatorCreated>()
                .When(s => s.Handle(trickleMultipleMessages))
                    .AssertSagaCompletionIs(false)
                .When(s => s.Handle(new ScheduledSmsSent { ConfirmationData = new SmsConfirmationData("r", DateTime.Now, 1m), ScheduledSmsId = sagaData.ScheduledMessageStatus[0].ScheduledSms.ScheduleMessageId }))
                    .AssertSagaCompletionIs(false)
                .When(s => s.Handle(new ScheduledSmsSent { ConfirmationData = new SmsConfirmationData("r", DateTime.Now, 1m), ScheduledSmsId = sagaData.ScheduledMessageStatus[1].ScheduledSms.ScheduleMessageId }))
                    .AssertSagaCompletionIs(false)
                    .ExpectPublish<CoordinatorCompleted>()
                .When(s => s.Handle(new ScheduledSmsFailed { ScheduledSmsId = sagaData.ScheduledMessageStatus[2].ScheduledSms.ScheduleMessageId }))
                    .AssertSagaCompletionIs(true);

            timingManager.VerifyAllExpectations();
            Assert.That(sagaData.MessagesScheduled, Is.EqualTo(3));
            Assert.That(sagaData.MessagesConfirmedSentOrFailed, Is.EqualTo(3));
        }
        public void TrickleMessagesRescheduleMessageSending_Data()
        {
            var ravenScheduleDocuments = MockRepository.GenerateMock<IRavenScheduleDocuments>();

            var dateTime = DateTime.Now;
            var finishTime = dateTime.AddMinutes(9);
            var sagaId = Guid.NewGuid();
            var sagaData = new CoordinateSmsSchedulingData { Originator = "o", OriginalScheduleStartTime = dateTime.AddMinutes(-5), CoordinatorId = sagaId};
            var pausedTrackedMessages = new List<ScheduleTrackingData>
                                            {
                                                new ScheduleTrackingData { MessageStatus = MessageStatus.Paused, ScheduleId = Guid.NewGuid()},
                                                new ScheduleTrackingData { MessageStatus = MessageStatus.Paused, ScheduleId = Guid.NewGuid()}
                                            };
            ravenScheduleDocuments.Expect(r => r.GetActiveScheduleTrackingData(sagaId)).Return(pausedTrackedMessages);

            var rescheduleTrickledMessages = new RescheduleTrickledMessages { ResumeTimeUtc = dateTime, FinishTimeUtc = finishTime};

            Test.Initialize();
            Test.Saga<CoordinateSmsScheduler>()
                .WithExternalDependencies(s =>
                {
                    s.Data = sagaData; s.RavenScheduleDocuments = ravenScheduleDocuments;
                })
                    .ExpectSend<RescheduleScheduledMessageWithNewTime>(
                        l =>
                        l.ScheduleMessageId == pausedTrackedMessages[0].ScheduleId &&
                        l.NewScheduleTimeUtc.Equals(dateTime))
                    .ExpectSend<RescheduleScheduledMessageWithNewTime>(
                        l =>
                        l.ScheduleMessageId == pausedTrackedMessages[1].ScheduleId &&
                        l.NewScheduleTimeUtc.Equals(finishTime))
                .When(s => s.Handle(rescheduleTrickledMessages));
        }
        public void TrickleMessagesSpacedByTimespan_Data()
        {
            var messageList = new List<SmsData> { new SmsData("9384938", "3943lasdkf;j"), new SmsData("99999", "dj;alsdfkj") };
            var trickleMessagesOverTime = new TrickleSmsWithDefinedTimeBetweenEachMessage {  TimeSpacing = new TimeSpan(1000), Messages = messageList, StartTimeUtc = DateTime.Now };

            var timingManager = MockRepository.GenerateMock<ICalculateSmsTiming>();

            var sagaData = new CoordinateSmsSchedulingData { Originator = "originator", Id = Guid.NewGuid() };
            Test.Initialize();
            Test.Saga<CoordinateSmsScheduler>()
                .WithExternalDependencies(s =>
                {
                    s.TimingManager = timingManager;
                    s.Data = sagaData;
                })
                    .ExpectSend<ScheduleSmsForSendingLater>(l =>
                        //l.Count == 2 &&
                        l.SendMessageAtUtc.Ticks == trickleMessagesOverTime.StartTimeUtc.ToUniversalTime().Ticks &&
                        l.SmsData.Message == trickleMessagesOverTime.Messages[0].Message &&
                        l.SmsData.Mobile == trickleMessagesOverTime.Messages[0].Mobile &&
                        l.SmsMetaData == trickleMessagesOverTime.MetaData)
                    .ExpectSend<ScheduleSmsForSendingLater>(l =>
                        l.SendMessageAtUtc.Ticks == trickleMessagesOverTime.StartTimeUtc.ToUniversalTime().Ticks + trickleMessagesOverTime.TimeSpacing.Ticks &&
                        l.SmsData.Message == trickleMessagesOverTime.Messages[1].Message &&
                        l.SmsData.Mobile == trickleMessagesOverTime.Messages[1].Mobile &&
                        l.SmsMetaData == trickleMessagesOverTime.MetaData)
                    .ExpectPublish<CoordinatorCreated>(c =>
                        c.CoordinatorId == sagaData.Id &&
                        c.ScheduledMessages.Count == 2 &&
                        c.ScheduledMessages[0].Number == trickleMessagesOverTime.Messages[0].Mobile &&
                        c.ScheduledMessages[0].ScheduleMessageId == sagaData.ScheduledMessageStatus[0].ScheduledSms.ScheduleMessageId &&
                        c.ScheduledMessages[0].ScheduleMessageId != Guid.Empty && // HACK : Need to make this valid
                        c.ScheduledMessages[0].ScheduledTimeUtc.Ticks == trickleMessagesOverTime.StartTimeUtc.ToUniversalTime().Ticks &&

                        c.ScheduledMessages[1].Number == trickleMessagesOverTime.Messages[1].Mobile &&
                        c.ScheduledMessages[1].ScheduleMessageId == sagaData.ScheduledMessageStatus[1].ScheduledSms.ScheduleMessageId &&
                        c.ScheduledMessages[1].ScheduleMessageId != Guid.Empty && // HACK : Need to make this valid
                        c.ScheduledMessages[1].ScheduledTimeUtc.Ticks == trickleMessagesOverTime.StartTimeUtc.ToUniversalTime().Ticks + trickleMessagesOverTime.TimeSpacing.Ticks)
                .When(s => s.Handle(trickleMessagesOverTime));

            Assert.That(sagaData.MessagesScheduled, Is.EqualTo(2));
            Assert.That(sagaData.ScheduledMessageStatus[0].MessageStatus, Is.EqualTo(MessageStatus.WaitingForScheduling));
            Assert.That(sagaData.ScheduledMessageStatus[1].MessageStatus, Is.EqualTo(MessageStatus.WaitingForScheduling));
            timingManager.VerifyAllExpectations();
        }
        public void TrickleMessagesResumeMessageSending_Data()
        {
            var messageList = new List<SmsData> { new SmsData("9384938", "3943lasdkf;j"), new SmsData("99999", "dj;alsdfkj"), new SmsData("mobile", "sent") };

            var timingManager = MockRepository.GenerateMock<ICalculateSmsTiming>();

            var scheduledMessageStatuses = new List<ScheduledMessageStatus>
            {
                new ScheduledMessageStatus(new ScheduleSmsForSendingLater { SmsData = messageList[0]}, MessageStatus.Paused),
                new ScheduledMessageStatus(new ScheduleSmsForSendingLater { SmsData = messageList[1]}, MessageStatus.Paused),
                new ScheduledMessageStatus(new ScheduleSmsForSendingLater { SmsData = messageList[2]}, MessageStatus.Sent)
            };
            var dateTime = DateTime.Now;
            var sagaData = new CoordinateSmsSchedulingData { Originator = "o", ScheduledMessageStatus = scheduledMessageStatuses, OriginalScheduleStartTime = dateTime.AddMinutes(-5) };

            var resumeTricklesMessages = new ResumeTrickledMessages { ResumeTimeUtc = dateTime };

            Test.Initialize();
            Test.Saga<CoordinateSmsScheduler>()
                .WithExternalDependencies(s =>
                {
                    s.TimingManager = timingManager;
                    s.Data = sagaData;
                })
                    .ExpectSend<ResumeScheduledMessageWithOffset>(
                        l =>
                        l.ScheduleMessageId == scheduledMessageStatuses[0].ScheduledSms.ScheduleMessageId &&
                        l.Offset == new TimeSpan(0, 0, 5, 0))
                    .ExpectSend<ResumeScheduledMessageWithOffset>(
                        l =>
                        l.ScheduleMessageId == scheduledMessageStatuses[1].ScheduledSms.ScheduleMessageId &&
                        l.Offset == new TimeSpan(0, 0, 5, 0))
                .When(s => s.Handle(resumeTricklesMessages));

            Assert.That(scheduledMessageStatuses[0].MessageStatus, Is.EqualTo(MessageStatus.Paused));
            Assert.That(scheduledMessageStatuses[1].MessageStatus, Is.EqualTo(MessageStatus.Paused));

            timingManager.VerifyAllExpectations();
        }
        public void TrickleMessagesResumeMessageSending_Data()
        {
            var ravenScheduleDocuments = MockRepository.GenerateMock<IRavenScheduleDocuments>();

            var timingManager = MockRepository.GenerateMock<ICalculateSmsTiming>();
            var dateTime = DateTime.Now;
            var sagaId = Guid.NewGuid();
            var sagaData = new CoordinateSmsSchedulingData { Originator = "o", OriginalScheduleStartTime = dateTime.AddMinutes(-5), CoordinatorId = sagaId };
            var pausedTrackedMessages = new List<ScheduleTrackingData>
                                            {
                                                new ScheduleTrackingData { MessageStatus = MessageStatus.Paused, ScheduleId = Guid.NewGuid()},
                                                new ScheduleTrackingData { MessageStatus = MessageStatus.Paused, ScheduleId = Guid.NewGuid()}
                                            };
            ravenScheduleDocuments.Expect(r => r.GetActiveScheduleTrackingData(sagaId)).Return(pausedTrackedMessages);

            var resumeTricklesMessages = new ResumeTrickledMessages { ResumeTimeUtc = dateTime };

            Test.Initialize();
            Test.Saga<CoordinateSmsScheduler>()
                .WithExternalDependencies(s =>
                {
                    s.TimingManager = timingManager;
                    s.Data = sagaData;
                    s.RavenScheduleDocuments = ravenScheduleDocuments;
                })
                    .ExpectSend<ResumeScheduledMessageWithOffset>(
                        l =>
                        l.ScheduleMessageId == pausedTrackedMessages[0].ScheduleId &&
                        l.Offset == new TimeSpan(0, 0, 5, 0))
                    .ExpectSend<ResumeScheduledMessageWithOffset>(
                        l =>
                        l.ScheduleMessageId == pausedTrackedMessages[1].ScheduleId &&
                        l.Offset == new TimeSpan(0, 0, 5, 0))
                .When(s => s.Handle(resumeTricklesMessages));

            timingManager.VerifyAllExpectations();
        }
        public void TrickleThreeMessagesFirstSentPausedThenResumed_SecondPauseMessageOutOfOrderIgnored()
        {
            var coordinatorId = Guid.NewGuid();
            var startTime = DateTime.Now.AddHours(3);
            var duration = new TimeSpan(0, 10, 0);
            var ravenScheduleDocuments = MockRepository.GenerateStrictMock<IRavenScheduleDocuments>();
            ravenScheduleDocuments.Expect(r => r.SaveSchedules(Arg<List<ScheduleSmsForSendingLater>>.Is.Anything, Arg<Guid>.Is.Anything));
            ravenScheduleDocuments.Expect(r => r.GetActiveScheduleTrackingData(coordinatorId)).Return(new List<ScheduleTrackingData> { new ScheduleTrackingData(), new ScheduleTrackingData() });
            ravenScheduleDocuments.Expect(r => r.GetActiveScheduleTrackingData(coordinatorId)).Return(new List<ScheduleTrackingData> { new ScheduleTrackingData(), new ScheduleTrackingData() });
            ravenScheduleDocuments.Expect(r => r.GetActiveScheduleTrackingData(coordinatorId)).Return(new List<ScheduleTrackingData>());
            ravenScheduleDocuments.Expect(r => r.AreCoordinatedSchedulesComplete(coordinatorId)).Return(true);
            ravenScheduleDocuments.Expect(r => r.SaveCoordinator(Arg<CoordinatorCreated>.Is.Anything));
            ravenScheduleDocuments.Expect(r => r.MarkCoordinatorAsComplete(Arg<Guid>.Is.Equal(coordinatorId), Arg<DateTime>.Is.Anything));
            ravenScheduleDocuments.Expect(r => r.GetScheduleSummary(coordinatorId)).Return(new List<ScheduledMessagesStatusCountInCoordinatorIndex.ReduceResult>());
            var trickleMultipleMessages = new TrickleSmsOverCalculatedIntervalsBetweenSetDates
            {
                StartTimeUtc = startTime,
                Messages = new List<SmsData>
                {
                    new SmsData("mobile#1", "message"),
                    new SmsData("mobile#2", "message2"),
                    new SmsData("mobile#3", "message3")
                },
                Duration = duration,
                CoordinatorId = coordinatorId,
                MetaData = new SmsMetaData()
            };

            var sagaData = new CoordinateSmsSchedulingData { Id = Guid.NewGuid(), Originator = "o", OriginalMessageId = "i" };
            Test.Initialize();
            Test.Saga<CoordinateSmsScheduler>()
                .WithExternalDependencies(d => { d.Data = sagaData; d.RavenScheduleDocuments = ravenScheduleDocuments; d.TimingManager = new CalculateSmsTiming(); })
                    .ExpectSend<ScheduleSmsForSendingLater>(l => l.SmsData.Mobile == trickleMultipleMessages.Messages[0].Mobile)
                    .ExpectSend<ScheduleSmsForSendingLater>(l => l.SmsData.Mobile == trickleMultipleMessages.Messages[1].Mobile)
                    .ExpectSend<ScheduleSmsForSendingLater>(l => l.SmsData.Mobile == trickleMultipleMessages.Messages[2].Mobile)
                    .ExpectTimeoutToBeSetAt<CoordinatorTimeout>((state, timeout) => true)
                .When(s => s.Handle(trickleMultipleMessages))
                    .ExpectSend<PauseScheduledMessageIndefinitely>()
                    .ExpectSend<PauseScheduledMessageIndefinitely>()
                .When(s => s.Handle(new PauseTrickledMessagesIndefinitely { MessageRequestTimeUtc = DateTime.Now.AddMinutes(-11) }))
                    .ExpectSend<ResumeScheduledMessageWithOffset>()
                    .ExpectSend<ResumeScheduledMessageWithOffset>()
                .When(s => s.Handle(new ResumeTrickledMessages { MessageRequestTimeUtc = DateTime.Now.AddMinutes(-10) }))
                    .ExpectNotSend<PauseScheduledMessageIndefinitely>(a => true)
                    .ExpectNotSend<PauseScheduledMessageIndefinitely>(a => true)
                .When(s => s.Handle(new PauseTrickledMessagesIndefinitely { MessageRequestTimeUtc = DateTime.Now.AddMinutes(-11) }))
                    .ExpectPublish<CoordinatorCompleted>()
                .When(s => s.Timeout(new CoordinatorTimeout()))
                .AssertSagaCompletionIs(true);
        }
        public void TrickleThreeMessagesOverTenMinutesOneMessageFailsCoordinatorStillCompletes()
        {
            var coordinatorId = Guid.NewGuid();
            var ravenScheduleDocuments = MockRepository.GenerateStrictMock<IRavenScheduleDocuments>();
            ravenScheduleDocuments.Expect(r => r.SaveCoordinator(Arg<CoordinatorCreated>.Is.Anything));
            ravenScheduleDocuments.Expect(r => r.SaveSchedules(Arg<List<ScheduleSmsForSendingLater>>.Is.Anything, Arg<Guid>.Is.Anything));
            ravenScheduleDocuments.Expect(r => r.AreCoordinatedSchedulesComplete(coordinatorId)).Return(true);
            ravenScheduleDocuments.Expect(r => r.MarkCoordinatorAsComplete(Arg<Guid>.Is.Equal(coordinatorId), Arg<DateTime>.Is.Anything));
            ravenScheduleDocuments.Expect(r => r.GetScheduleSummary(coordinatorId)).Return(new List<ScheduledMessagesStatusCountInCoordinatorIndex.ReduceResult>());
            var startTime = DateTime.Now.AddHours(3);
            var duration = new TimeSpan(0, 10, 0);
            var trickleMultipleMessages = new TrickleSmsOverCalculatedIntervalsBetweenSetDates
            {
                StartTimeUtc = startTime,
                Messages = new List<SmsData>
                {
                    new SmsData("mobile#1", "message"),
                    new SmsData("mobile#2", "message2"),
                    new SmsData("mobile#3", "message3")
                },
                Duration = duration,
                CoordinatorId = coordinatorId,
                MetaData = new SmsMetaData()
            };

            var timingManager = MockRepository.GenerateMock<ICalculateSmsTiming>();
            var messageTiming = new List<DateTime> { startTime, startTime.AddMinutes(5), startTime.AddMinutes(10) };
            timingManager.Expect(t => t.CalculateTiming(startTime, duration, 3))
                .Return(messageTiming);

            var sagaData = new CoordinateSmsSchedulingData { Id = Guid.NewGuid(), Originator = "o", OriginalMessageId = "i" };
            Test.Initialize();
            Test.Saga<CoordinateSmsScheduler>()
                .WithExternalDependencies(s =>
                    {
                        s.TimingManager = timingManager;
                        s.Data = sagaData;
                        s.RavenScheduleDocuments = ravenScheduleDocuments;
                    })
                    .ExpectSend<ScheduleSmsForSendingLater>(l => l.SmsData.Mobile == trickleMultipleMessages.Messages[0].Mobile)
                    .ExpectSend<ScheduleSmsForSendingLater>(l => l.SmsData.Mobile == trickleMultipleMessages.Messages[1].Mobile)
                    .ExpectSend<ScheduleSmsForSendingLater>(l => l.SmsData.Mobile == trickleMultipleMessages.Messages[2].Mobile)
                    .ExpectPublish<CoordinatorCreated>()
                    .ExpectTimeoutToBeSetAt<CoordinatorTimeout>((state, timeout) => true)
                .When(s => s.Handle(trickleMultipleMessages))
                    .AssertSagaCompletionIs(false)
                    .ExpectPublish<CoordinatorCompleted>()
                .When(s => s.Timeout(new CoordinatorTimeout()))
                .AssertSagaCompletionIs(true);

            timingManager.VerifyAllExpectations();
        }
        public void TrickleMessagesPauseMessagesIndefinitely_Data()
        {
            var ravenScheduleDocuments = MockRepository.GenerateMock<IRavenScheduleDocuments>();

            var pauseMessageSending = new PauseTrickledMessagesIndefinitely();

            var timingManager = MockRepository.GenerateMock<ICalculateSmsTiming>();

            var sagaId = Guid.NewGuid();
            var sagaData = new CoordinateSmsSchedulingData { Id = Guid.NewGuid(), Originator = "o", OriginalMessageId = "i", CoordinatorId = sagaId };
            var pausedTrackedMessages = new List<ScheduleTrackingData>
                                            {
                                                new ScheduleTrackingData { MessageStatus = MessageStatus.Scheduled, ScheduleId = Guid.NewGuid()},
                                                new ScheduleTrackingData { MessageStatus = MessageStatus.Scheduled, ScheduleId = Guid.NewGuid()}
                                            };
            ravenScheduleDocuments.Expect(r => r.GetActiveScheduleTrackingData(sagaId)).Return(pausedTrackedMessages);

            Test.Initialize();
            Test.Saga<CoordinateSmsScheduler>()
                .WithExternalDependencies(s =>
                {
                    s.TimingManager = timingManager;
                    s.Data = sagaData;
                    s.RavenScheduleDocuments = ravenScheduleDocuments;
                })
                    .ExpectSend<PauseScheduledMessageIndefinitely>(l => l.ScheduleMessageId == pausedTrackedMessages[0].ScheduleId)
                    .ExpectSend<PauseScheduledMessageIndefinitely>(l => l.ScheduleMessageId == pausedTrackedMessages[1].ScheduleId)
                .When(s => s.Handle(pauseMessageSending));

            timingManager.VerifyAllExpectations();
        }
        public void SendAllAtOnce_Data()
        {
            var messageList = new List<SmsData> { new SmsData("9384938", "3943lasdkf;j"), new SmsData("99999", "dj;alsdfkj")};
            var sendTimeUtc = DateTime.Now;
            var sendAllMessagesAtOnce = new SendAllMessagesAtOnce { Messages = messageList, SendTimeUtc = sendTimeUtc, UserOlsenTimeZone = "timeZone", CoordinatorId = Guid.NewGuid(), MetaData = new SmsMetaData()};

            var ravenScheduleDocuments = MockRepository.GenerateStrictMock<IRavenScheduleDocuments>();
            var sendingMessages = new List<ScheduleSmsForSendingLater>();
            ravenScheduleDocuments.Expect(r => r.SaveSchedules(Arg<List<ScheduleSmsForSendingLater>>.Is.NotNull, Arg<Guid>.Is.Equal(sendAllMessagesAtOnce.CoordinatorId)))
                .WhenCalled(r => sendingMessages = (List<ScheduleSmsForSendingLater>)r.Arguments[0]);
            ravenScheduleDocuments.Expect(r => r.SaveCoordinator(Arg<CoordinatorCreated>.Is.Anything));

            var timingManager = MockRepository.GenerateMock<ICalculateSmsTiming>();

            var sagaData = new CoordinateSmsSchedulingData { Originator = "originator", Id = Guid.NewGuid() };
            Test.Initialize();
            Test.Saga<CoordinateSmsScheduler>()
                .WithExternalDependencies(s =>
                {
                    s.TimingManager = timingManager;
                    s.Data = sagaData;
                    s.RavenScheduleDocuments = ravenScheduleDocuments;
                })
                    .ExpectSend<ScheduleSmsForSendingLater>(l =>
                        l.SendMessageAtUtc == sendTimeUtc &&
                        l.SmsData.Message == sendAllMessagesAtOnce.Messages[0].Message &&
                        l.SmsData.Mobile == sendAllMessagesAtOnce.Messages[0].Mobile &&
                        l.SmsMetaData == sendAllMessagesAtOnce.MetaData)
                    .ExpectSend<ScheduleSmsForSendingLater>(l =>
                        l.SendMessageAtUtc == sendTimeUtc &&
                        l.SmsData.Message == sendAllMessagesAtOnce.Messages[1].Message &&
                        l.SmsData.Mobile == sendAllMessagesAtOnce.Messages[1].Mobile &&
                        l.SmsMetaData == sendAllMessagesAtOnce.MetaData)
                    .ExpectPublish<CoordinatorCreated>(c =>
                        c.CoordinatorId == sendAllMessagesAtOnce.CoordinatorId &&
                        c.ScheduledMessages.Count == 2 &&
                        c.ScheduledMessages[0].Number == sendAllMessagesAtOnce.Messages[0].Mobile &&
                        c.ScheduledMessages[0].ScheduleMessageId == sendingMessages[0].ScheduleMessageId &&
                        c.ScheduledMessages[0].ScheduleMessageId != Guid.Empty &&
                        c.ScheduledMessages[0].ScheduledTimeUtc == sendTimeUtc &&

                        c.ScheduledMessages[1].Number == sendAllMessagesAtOnce.Messages[1].Mobile &&
                        c.ScheduledMessages[1].ScheduleMessageId == sendingMessages[1].ScheduleMessageId &&
                        c.ScheduledMessages[1].ScheduleMessageId != Guid.Empty &&
                        c.ScheduledMessages[1].ScheduledTimeUtc == sendTimeUtc &&
                        c.UserOlsenTimeZone == sendAllMessagesAtOnce.UserOlsenTimeZone)
                    .ExpectTimeoutToBeSetAt<CoordinatorTimeout>((state, timeout) => timeout == sendAllMessagesAtOnce.SendTimeUtc.AddMinutes(2))
                .When(s => s.Handle(sendAllMessagesAtOnce));

            Assert.That(sendingMessages.Count, Is.EqualTo(2));
            timingManager.VerifyAllExpectations();
        }
        public void TrickleMessagesPauseMessagesIndefinitely_Data()
        {
            var messageList = new List<SmsData> { new SmsData("9384938", "3943lasdkf;j"), new SmsData("99999", "dj;alsdfkj"), new SmsData("mobile", "sent") };

            var pauseMessageSending = new PauseTrickledMessagesIndefinitely();

            var timingManager = MockRepository.GenerateMock<ICalculateSmsTiming>();

            var scheduledMessageStatuses = new List<ScheduledMessageStatus>
            {
                new ScheduledMessageStatus(new ScheduleSmsForSendingLater { SmsData = messageList[0]}),
                new ScheduledMessageStatus(new ScheduleSmsForSendingLater { SmsData = messageList[1]}, MessageStatus.Scheduled),
                new ScheduledMessageStatus(new ScheduleSmsForSendingLater { SmsData = messageList[2]}, MessageStatus.Sent)
            };

            var sagaData = new CoordinateSmsSchedulingData { ScheduledMessageStatus = scheduledMessageStatuses, Id = Guid.NewGuid(), Originator = "o", OriginalMessageId = "i" };

            Test.Initialize();
            Test.Saga<CoordinateSmsScheduler>()
                .WithExternalDependencies(s =>
                {
                    s.TimingManager = timingManager;
                    s.Data = sagaData;
                })
                    .ExpectSend<PauseScheduledMessageIndefinitely>(
                        l => l.ScheduleMessageId == scheduledMessageStatuses[0].ScheduledSms.ScheduleMessageId)
                    .ExpectSend<PauseScheduledMessageIndefinitely>(l =>
                        l.ScheduleMessageId == scheduledMessageStatuses[1].ScheduledSms.ScheduleMessageId)
                .When(s => s.Handle(pauseMessageSending));

            Assert.That(sagaData.ScheduledMessageStatus[0].MessageStatus, Is.EqualTo(MessageStatus.WaitingForScheduling));
            Assert.That(sagaData.ScheduledMessageStatus[1].MessageStatus, Is.EqualTo(MessageStatus.Scheduled));

            timingManager.VerifyAllExpectations();
        }
        public void TrickleThreeMessagesSpacedAMinuteApartPausedAfterFirstThenRescheduled()
        {
            var coordinatorId = Guid.NewGuid();
            var ravenScheduleDocuments = MockRepository.GenerateStrictMock<IRavenScheduleDocuments>();
            ravenScheduleDocuments.Expect(r => r.SaveSchedules(Arg<List<ScheduleSmsForSendingLater>>.Is.Anything, Arg<Guid>.Is.Anything));
            ravenScheduleDocuments.Expect(r => r.SaveCoordinator(Arg<CoordinatorCreated>.Is.Anything));
            ravenScheduleDocuments.Expect(r => r.GetActiveScheduleTrackingData(coordinatorId)).Return(new List<ScheduleTrackingData> { new ScheduleTrackingData(), new ScheduleTrackingData() });
            ravenScheduleDocuments.Expect(r => r.GetActiveScheduleTrackingData(coordinatorId)).Return(new List<ScheduleTrackingData> { new ScheduleTrackingData(), new ScheduleTrackingData() });
            ravenScheduleDocuments.Expect(r => r.AreCoordinatedSchedulesComplete(coordinatorId)).Return(true);
            ravenScheduleDocuments.Expect(r => r.MarkCoordinatorAsComplete(Arg<Guid>.Is.Equal(coordinatorId), Arg<DateTime>.Is.Anything));
            ravenScheduleDocuments.Expect(r => r.GetScheduleSummary(coordinatorId)).Return(new List<ScheduledMessagesStatusCountInCoordinatorIndex.ReduceResult>());
            var startTime = DateTime.Now.AddHours(3);
            var timeSpacing = new TimeSpan(0, 10, 0);
            var trickleMultipleMessages = new TrickleSmsWithDefinedTimeBetweenEachMessage
            {
                StartTimeUtc = startTime,
                Messages = new List<SmsData>
                {
                    new SmsData("mobile#1", "message"),
                    new SmsData("mobile#2", "message2"),
                    new SmsData("mobile#3", "message3")
                },
                TimeSpacing = timeSpacing,
                CoordinatorId = coordinatorId,
                MetaData = new SmsMetaData()
            };

            var sagaData = new CoordinateSmsSchedulingData { Id = Guid.NewGuid(), Originator = "o", OriginalMessageId = "i" };
            Test.Initialize();
            Test.Saga<CoordinateSmsScheduler>()
                .WithExternalDependencies(d => { d.Data = sagaData; d.RavenScheduleDocuments = ravenScheduleDocuments; })
                    .ExpectSend<ScheduleSmsForSendingLater>(l => l.SmsData.Mobile == trickleMultipleMessages.Messages[0].Mobile)
                    .ExpectSend<ScheduleSmsForSendingLater>(l => l.SmsData.Mobile == trickleMultipleMessages.Messages[1].Mobile)
                    .ExpectSend<ScheduleSmsForSendingLater>(l => l.SmsData.Mobile == trickleMultipleMessages.Messages[2].Mobile)
                    .ExpectTimeoutToBeSetAt<CoordinatorTimeout>((state, timeout) => true)
                .When(s => s.Handle(trickleMultipleMessages))
                    .ExpectSend<PauseScheduledMessageIndefinitely>()
                    .ExpectSend<PauseScheduledMessageIndefinitely>()
                .When(s => s.Handle(new PauseTrickledMessagesIndefinitely()))
                    .ExpectSend<RescheduleScheduledMessageWithNewTime>()
                    .ExpectSend<RescheduleScheduledMessageWithNewTime>()
                .When(s => s.Handle(new RescheduleTrickledMessages()))
                    .AssertSagaCompletionIs(false)
                    .ExpectPublish<CoordinatorCompleted>()
                .When(s => s.Timeout(new CoordinatorTimeout()))
                .AssertSagaCompletionIs(true);
        }