public async Task UpdateLeaseAsync_ShouldReturnNull_IfMergerReturnsNull()
        {
            var client  = Mock.Of <IChangeFeedDocumentClient>();
            var updater = new DocumentServiceLeaseUpdater(client);
            var lease   = Mock.Of <ILease>();

            var newLease = await updater.UpdateLeaseAsync(lease, documentUri, null, serverLease => null, true);

            Assert.Null(newLease);
        }
        private async Task <Exception> TestReplaceException(Exception replaceException)
        {
            ILease oldLease     = CreateLease();
            ILease updatedLease = CreateLease(eTag1);

            var client = Mock.Of <IChangeFeedDocumentClient>();

            Mock.Get(client)
            .Setup(c => c.ReplaceDocumentAsync(
                       documentUri,
                       updatedLease,
                       It.Is <RequestOptions>(options => options.AccessCondition.Type == AccessConditionType.IfMatch && options.AccessCondition.Condition == eTag1)))
            .ThrowsAsync(replaceException);
            var updater = new DocumentServiceLeaseUpdater(client);

            return(await Record.ExceptionAsync(async() => await updater.UpdateLeaseAsync(oldLease, documentUri, serverLease => updatedLease)));
        }
        private async Task <Exception> TestReadException(Exception readException)
        {
            ILease oldLease     = CreateLease();
            ILease updatedLease = CreateLease(eTag1);

            var client = Mock.Of <IChangeFeedDocumentClient>();

            SetupReplaceConflict(client, updatedLease);
            Mock.Get(client)
            .Setup(c => c.ReadDocumentAsync(documentUri, null, default(CancellationToken)))
            .ThrowsAsync(readException).Verifiable();

            var       updater   = new DocumentServiceLeaseUpdater(client);
            Exception exception = await Record.ExceptionAsync(async() => await updater.UpdateLeaseAsync(oldLease, documentUri, null, serverLease => updatedLease, true));

            Mock.Get(client).VerifyAll();
            return(exception);
        }
        public async Task UpdateLeaseAsync_ShouldReturnNewLease_WhenReplaceSucceeds()
        {
            ILease oldLease     = CreateLease();
            ILease updatedLease = CreateLease(eTag1);

            var client = Mock.Of <IChangeFeedDocumentClient>();

            Mock.Get(client)
            .Setup(c => c.ReplaceDocumentAsync(
                       documentUri,
                       updatedLease,
                       It.Is <RequestOptions>(options => options.AccessCondition.Type == AccessConditionType.IfMatch && options.AccessCondition.Condition == eTag1)))
            .ReturnsAsync(CreateLeaseResponse(eTag2));
            var updater = new DocumentServiceLeaseUpdater(client);

            var newLease = await updater.UpdateLeaseAsync(oldLease, documentUri, serverLease => updatedLease);

            Assert.Equal(eTag2, newLease.ConcurrencyToken);
        }
        public async Task UpdateLeaseAsync_ShouldRetryWithUpdatedLease_WhenConflict()
        {
            var    client   = Mock.Of <IChangeFeedDocumentClient>();
            var    updater  = new DocumentServiceLeaseUpdater(client);
            ILease oldLease = CreateLease();

            // setup pass #1
            ILease updatedLease1 = CreateLease(eTag1);

            SetupReplaceConflict(client, updatedLease1);
            Mock.Get(client)
            .Setup(c => c.ReadDocumentAsync(documentUri, null, default(CancellationToken)))
            .ReturnsAsync(CreateLeaseResponse(eTag2));

            // setup pass #2
            ILease updatedLease2 = CreateLease(eTag2);

            Mock.Get(client)
            .Setup(c => c.ReplaceDocumentAsync(
                       documentUri,
                       updatedLease2,
                       It.Is <RequestOptions>(options => options.AccessCondition.Type == AccessConditionType.IfMatch && options.AccessCondition.Condition == eTag2),
                       default(CancellationToken)))
            .ReturnsAsync(CreateLeaseResponse(eTag3));

            ILease lease = await updater.UpdateLeaseAsync(oldLease, documentUri, null, serverLease =>
            {
                if (serverLease.ConcurrencyToken == null)
                {
                    return(updatedLease1);
                }
                if (serverLease.ConcurrencyToken == eTag2)
                {
                    return(updatedLease2);
                }
                throw new InvalidOperationException();
            }, true);

            Assert.Equal(eTag3, lease.ConcurrencyToken);
        }
        public async Task UpdateLeaseAsync_ShouldThrowLeaseLostException_WhenConflictAfterAllRetries()
        {
            var       client              = Mock.Of <IChangeFeedDocumentClient>();
            var       updater             = new DocumentServiceLeaseUpdater(client);
            ILease    oldLease            = CreateLease();
            const int retryCount          = 5;
            var       getDocumentSequence = Mock.Get(client)
                                            .SetupSequence(c => c.ReadDocumentAsync(documentUri, null, default(CancellationToken)));

            for (int i = 0; i <= retryCount; i++)
            {
                string eTag = i.ToString();
                Mock.Get(client)
                .Setup(c => c.ReplaceDocumentAsync(
                           documentUri,
                           It.Is <ILease>(lease => lease.ConcurrencyToken == eTag),
                           It.Is <RequestOptions>(options => options.AccessCondition.Type == AccessConditionType.IfMatch && options.AccessCondition.Condition == eTag),
                           default(CancellationToken)))
                .ThrowsAsync(DocumentExceptionHelpers.CreatePreconditionFailedException());
                getDocumentSequence = getDocumentSequence.ReturnsAsync(CreateLeaseResponse(eTag));
            }

            int       callbackInvokeCount = 0;
            Exception exception           = await Record.ExceptionAsync(async() => await updater.UpdateLeaseAsync(oldLease, documentUri, null, serverLease =>
            {
                callbackInvokeCount++;
                if (serverLease.ConcurrencyToken == null)
                {
                    return(CreateLease("0"));
                }
                return(CreateLease((int.Parse(serverLease.ConcurrencyToken) + 1).ToString()));
            }, true));

            Assert.IsAssignableFrom <LeaseLostException>(exception);
            Assert.Equal(retryCount + 1, callbackInvokeCount);
        }