public async Task WhenMultipleCreatorSubscriptions_ItShouldPassTheOutputCommittedAccountBalanceDownTheChain()
        {
            var creatorsAndFirstSubscribedDates = new List <CreatorIdAndFirstSubscribedDate>
            {
                new CreatorIdAndFirstSubscribedDate(CreatorId1, FirstSubscribedDate1),
                new CreatorIdAndFirstSubscribedDate(CreatorId2, FirstSubscribedDate2),
            };

            this.getCreatorsAndFirstSubscribedDates.Setup(v => v.ExecuteAsync(SubscriberId))
            .ReturnsAsync(creatorsAndFirstSubscribedDates);

            var committedAccountBalance = new CommittedAccountBalance(10m);

            this.getCommittedAccountBalanceDbStatement.Setup(v => v.ExecuteAsync(SubscriberId)).ReturnsAsync(committedAccountBalance.Amount);

            this.getLatestCommittedLedgerDate.Setup(v => v.ExecuteAsync(SubscriberId, CreatorId1))
            .ReturnsAsync(LastCommittedLedgerDate1);

            this.getLatestCommittedLedgerDate.Setup(v => v.ExecuteAsync(SubscriberId, CreatorId2))
            .ReturnsAsync(LastCommittedLedgerDate2);

            var resultCommittedAccountBalance1 = new CommittedAccountBalance(5m);

            this.processPaymentsBetweenSubscriberAndCreator.Setup(
                v => v.ExecuteAsync(
                    SubscriberId,
                    CreatorId1,
                    LastCommittedLedgerDate1,
                    EndTimeExclusive,
                    committedAccountBalance))
            .ReturnsAsync(resultCommittedAccountBalance1).Verifiable();

            var resultCommittedAccountBalance2 = new CommittedAccountBalance(2m);

            this.processPaymentsBetweenSubscriberAndCreator.Setup(
                v => v.ExecuteAsync(
                    SubscriberId,
                    CreatorId2,
                    LastCommittedLedgerDate2,
                    EndTimeExclusive,
                    resultCommittedAccountBalance1))
            .ReturnsAsync(resultCommittedAccountBalance2).Verifiable();

            var errors = new List <PaymentProcessingException>();

            await this.target.ExecuteAsync(SubscriberId, EndTimeExclusive, this.keepAliveHandler.Object, errors);

            Assert.AreEqual(0, errors.Count);

            this.processPaymentsBetweenSubscriberAndCreator.Verify();

            this.keepAliveHandler.Verify(v => v.KeepAliveAsync(), Times.Exactly(2));
        }
        public async Task WhenAnErrorOccurs_ItShouldLogTheErrorAndContinueProcessing()
        {
            var creatorsAndFirstSubscribedDates = new List <CreatorIdAndFirstSubscribedDate>
            {
                new CreatorIdAndFirstSubscribedDate(CreatorId1, FirstSubscribedDate1),
                new CreatorIdAndFirstSubscribedDate(CreatorId2, FirstSubscribedDate2),
            };

            this.getCreatorsAndFirstSubscribedDates.Setup(v => v.ExecuteAsync(SubscriberId))
            .ReturnsAsync(creatorsAndFirstSubscribedDates);

            var committedAccountBalance = new CommittedAccountBalance(10m);

            this.getCommittedAccountBalanceDbStatement.Setup(v => v.ExecuteAsync(SubscriberId)).ReturnsAsync(committedAccountBalance.Amount);

            var exception = new DivideByZeroException();

            this.getLatestCommittedLedgerDate.Setup(v => v.ExecuteAsync(SubscriberId, CreatorId1))
            .Throws(exception);
            this.getLatestCommittedLedgerDate.Setup(v => v.ExecuteAsync(SubscriberId, CreatorId2))
            .ReturnsAsync(null);

            this.processPaymentsBetweenSubscriberAndCreator.Setup(
                v => v.ExecuteAsync(
                    SubscriberId,
                    CreatorId2,
                    StartDateCalculatedFromFirstSubscribedDate2,
                    EndTimeExclusive,
                    committedAccountBalance))
            .ReturnsAsync(new CommittedAccountBalance(5m)).Verifiable();

            var errors = new List <PaymentProcessingException>();

            await this.target.ExecuteAsync(SubscriberId, EndTimeExclusive, this.keepAliveHandler.Object, errors);

            Assert.AreEqual(1, errors.Count);
            Assert.AreEqual(CreatorId1, errors[0].CreatorId);
            Assert.AreEqual(SubscriberId, errors[0].SubscriberId);
            Assert.AreSame(exception, errors[0].InnerException);

            this.processPaymentsBetweenSubscriberAndCreator.Verify();

            this.keepAliveHandler.Verify(v => v.KeepAliveAsync(), Times.Exactly(2));
        }
        public async Task WhenProcessingTimePeriodIsTooShort_ItShouldSkipCreatorAndContinueProcessing()
        {
            var creatorsAndFirstSubscribedDates = new List <CreatorIdAndFirstSubscribedDate>
            {
                new CreatorIdAndFirstSubscribedDate(CreatorId1, FirstSubscribedDate1),
                new CreatorIdAndFirstSubscribedDate(CreatorId2, FirstSubscribedDate2),
            };

            this.getCreatorsAndFirstSubscribedDates.Setup(v => v.ExecuteAsync(SubscriberId))
            .ReturnsAsync(creatorsAndFirstSubscribedDates);

            var committedAccountBalance = new CommittedAccountBalance(10m);

            this.getCommittedAccountBalanceDbStatement.Setup(v => v.ExecuteAsync(SubscriberId)).ReturnsAsync(committedAccountBalance.Amount);

            this.getLatestCommittedLedgerDate.Setup(v => v.ExecuteAsync(SubscriberId, CreatorId1))
            .ReturnsAsync(EndTimeExclusive.Subtract(ProcessPaymentsForSubscriber.MinimumProcessingPeriod));

            this.getLatestCommittedLedgerDate.Setup(v => v.ExecuteAsync(SubscriberId, CreatorId2))
            .ReturnsAsync(null);

            this.processPaymentsBetweenSubscriberAndCreator.Setup(
                v => v.ExecuteAsync(
                    SubscriberId,
                    CreatorId2,
                    StartDateCalculatedFromFirstSubscribedDate2,
                    EndTimeExclusive,
                    committedAccountBalance))
            .ReturnsAsync(new CommittedAccountBalance(5m)).Verifiable();

            var errors = new List <PaymentProcessingException>();

            await this.target.ExecuteAsync(SubscriberId, EndTimeExclusive, this.keepAliveHandler.Object, errors);

            Assert.AreEqual(0, errors.Count);

            this.processPaymentsBetweenSubscriberAndCreator.Verify();

            this.keepAliveHandler.Verify(v => v.KeepAliveAsync(), Times.Exactly(2));
        }
        public async Task WhenCommittedAccountBalanceIsNegative_ItShouldLogAnErrorAndContinue()
        {
            var creatorsAndFirstSubscribedDates = new List <CreatorIdAndFirstSubscribedDate>
            {
                new CreatorIdAndFirstSubscribedDate(CreatorId1, FirstSubscribedDate1),
            };

            this.getCreatorsAndFirstSubscribedDates.Setup(v => v.ExecuteAsync(SubscriberId))
            .ReturnsAsync(creatorsAndFirstSubscribedDates);

            var committedAccountBalance = new CommittedAccountBalance(10m);

            this.getCommittedAccountBalanceDbStatement.Setup(v => v.ExecuteAsync(SubscriberId)).ReturnsAsync(committedAccountBalance.Amount);

            this.getLatestCommittedLedgerDate.Setup(v => v.ExecuteAsync(SubscriberId, CreatorId1))
            .ReturnsAsync(LastCommittedLedgerDate1);

            var resultCommittedAccountBalance = new CommittedAccountBalance(5m);

            this.processPaymentsBetweenSubscriberAndCreator.Setup(
                v => v.ExecuteAsync(
                    SubscriberId,
                    CreatorId1,
                    LastCommittedLedgerDate1,
                    EndTimeExclusive,
                    committedAccountBalance))
            .ReturnsAsync(resultCommittedAccountBalance).Verifiable();

            var errors = new List <PaymentProcessingException>();

            await this.target.ExecuteAsync(SubscriberId, EndTimeExclusive, this.keepAliveHandler.Object, errors);

            Assert.AreEqual(0, errors.Count);

            this.processPaymentsBetweenSubscriberAndCreator.Verify();

            this.keepAliveHandler.Verify(v => v.KeepAliveAsync(), Times.Once);
        }
        public async Task WhenLatestCommittedLedgerDateDoesNotExist_ItShouldUseFirstSubscribedDateToCalculateStartDate()
        {
            var creatorsAndFirstSubscribedDates = new List <CreatorIdAndFirstSubscribedDate>
            {
                new CreatorIdAndFirstSubscribedDate(CreatorId1, FirstSubscribedDate1),
            };

            this.getCreatorsAndFirstSubscribedDates.Setup(v => v.ExecuteAsync(SubscriberId))
            .ReturnsAsync(creatorsAndFirstSubscribedDates);

            var committedAccountBalance = new CommittedAccountBalance(10m);

            this.getCommittedAccountBalanceDbStatement.Setup(v => v.ExecuteAsync(SubscriberId)).ReturnsAsync(committedAccountBalance.Amount);

            this.getLatestCommittedLedgerDate.Setup(v => v.ExecuteAsync(SubscriberId, CreatorId1))
            .ReturnsAsync(null);

            this.processPaymentsBetweenSubscriberAndCreator.Setup(
                v => v.ExecuteAsync(
                    SubscriberId,
                    CreatorId1,
                    StartDateCalculatedFromFirstSubscribedDate1,
                    EndTimeExclusive,
                    committedAccountBalance))
            .ReturnsAsync(new CommittedAccountBalance(5m)).Verifiable();

            var errors = new List <PaymentProcessingException>();

            await this.target.ExecuteAsync(SubscriberId, EndTimeExclusive, this.keepAliveHandler.Object, errors);

            Assert.AreEqual(0, errors.Count);

            this.processPaymentsBetweenSubscriberAndCreator.Verify();

            this.keepAliveHandler.Verify(v => v.KeepAliveAsync(), Times.Once);
        }