public async Task ChangeFeedIteratorCore_ReadNextAsync()
        {
            int numItems = 100;
            IDocumentContainer documentContainer = await CreateDocumentContainerAsync(numItems);

            ChangeFeedIteratorCore changeFeedIteratorCore = new ChangeFeedIteratorCore(
                documentContainer,
                new ChangeFeedRequestOptions(),
                ChangeFeedStartFrom.Beginning());

            int count = 0;

            while (changeFeedIteratorCore.HasMoreResults)
            {
                ResponseMessage responseMessage = await changeFeedIteratorCore.ReadNextAsync();

                if (responseMessage.StatusCode == HttpStatusCode.NotModified)
                {
                    break;
                }

                count += GetChanges(responseMessage.Content).Count;
            }

            Assert.AreEqual(numItems, count);
        }
        public async Task ChangeFeedIteratorCore_HandlesSplitsThroughPipeline()
        {
            int numItems = 100;
            IDocumentContainer documentContainer = await CreateDocumentContainerAsync(numItems);

            ChangeFeedIteratorCore changeFeedIteratorCore = new ChangeFeedIteratorCore(
                documentContainer,
                new ChangeFeedRequestOptions(),
                ChangeFeedStartFrom.Beginning());

            int    seed   = new Random().Next();
            Random random = new Random(seed);

            int count = 0;

            while (changeFeedIteratorCore.HasMoreResults)
            {
                ResponseMessage responseMessage = await changeFeedIteratorCore.ReadNextAsync();

                if (responseMessage.StatusCode == HttpStatusCode.NotModified)
                {
                    break;
                }

                count += GetChanges(responseMessage.Content).Count;

                await documentContainer.RefreshProviderAsync(NoOpTrace.Singleton, cancellationToken : default);

                IReadOnlyList <FeedRangeInternal> ranges = await documentContainer.GetFeedRangesAsync(trace : NoOpTrace.Singleton, cancellationToken : default);
예제 #3
0
        public async Task ChangeFeedIteratorCore_BreathFirst()
        {
            int expected = 500;
            List <CompositeContinuationToken> previousToken = null;

            await this.CreateRandomItems(this.LargerContainer, expected, randomPartitionKey : true);

            ContainerInternal      itemsCore    = this.LargerContainer;
            ChangeFeedIteratorCore feedIterator = itemsCore.GetChangeFeedStreamIterator(changeFeedRequestOptions: new ChangeFeedRequestOptions()
            {
                MaxItemCount = 1,
                From         = ChangeFeedRequestOptions.StartFrom.CreateFromBeginning(),
            }) as ChangeFeedIteratorCore;

            while (true)
            {
                using (ResponseMessage responseMessage =
                           await feedIterator.ReadNextAsync(this.cancellationToken))
                {
                    Assert.IsTrue(FeedRangeCompositeContinuation.TryParse(responseMessage.ContinuationToken, out FeedRangeContinuation continuation));
                    FeedRangeCompositeContinuation    compositeContinuation = continuation as FeedRangeCompositeContinuation;
                    List <CompositeContinuationToken> deserializedToken     = compositeContinuation.CompositeContinuationTokens.ToList();
                    if (previousToken != null)
                    {
                        // Verify that the token, even though it yielded results, it moved to a new range
                        Assert.AreNotEqual(previousToken[0].Range.Min, deserializedToken[0].Range.Min);
                        Assert.AreNotEqual(previousToken[0].Range.Max, deserializedToken[0].Range.Max);
                        break;
                    }

                    previousToken = deserializedToken;
                }
            }
        }
        public async Task ChangeFeedIteratorCore_BreathFirst()
        {
            int expected = 500;
            List <CompositeContinuationToken> previousToken = null;

            await this.CreateRandomItems(this.LargerContainer, expected, randomPartitionKey : true);

            ContainerCore          itemsCore    = this.LargerContainer;
            ChangeFeedIteratorCore feedIterator = itemsCore.GetChangeFeedStreamIterator(changeFeedRequestOptions: new ChangeFeedRequestOptions()
            {
                StartTime = DateTime.MinValue.ToUniversalTime(), MaxItemCount = 1
            }) as ChangeFeedIteratorCore;

            while (true)
            {
                using (ResponseMessage responseMessage =
                           await feedIterator.ReadNextAsync(this.cancellationToken))
                {
                    FeedTokenEPKRange feedToken = feedIterator.FeedToken as FeedTokenEPKRange;
                    List <CompositeContinuationToken> deserializedToken = feedToken.CompositeContinuationTokens.ToList();
                    if (previousToken != null)
                    {
                        // Verify that the token, even though it yielded results, it moved to a new range
                        Assert.AreNotEqual(previousToken[0].Range.Min, deserializedToken[0].Range.Min);
                        Assert.AreNotEqual(previousToken[0].Range.Max, deserializedToken[0].Range.Max);
                        break;
                    }

                    previousToken = deserializedToken;
                }
            }
        }
        public async Task ChangeFeedIteratorCore_WithMaxItemCount()
        {
            await this.CreateRandomItems(this.Container, 2, randomPartitionKey : true);

            ContainerCore          itemsCore    = this.Container;
            ChangeFeedIteratorCore feedIterator = itemsCore.GetChangeFeedStreamIterator(changeFeedRequestOptions: new ChangeFeedRequestOptions()
            {
                MaxItemCount = 1, StartTime = DateTime.MinValue.ToUniversalTime()
            }) as ChangeFeedIteratorCore;

            while (feedIterator.HasMoreResults)
            {
                using (ResponseMessage responseMessage =
                           await feedIterator.ReadNextAsync(this.cancellationToken))
                {
                    if (responseMessage.IsSuccessStatusCode)
                    {
                        Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(responseMessage.Content).Data;
                        if (response.Count > 0)
                        {
                            Assert.AreEqual(1, response.Count);
                            return;
                        }
                    }
                }
            }

            Assert.Fail("Found no batch with size 1");
        }
        public async Task ChangeFeedIteratorCore_EmptyBeginning()
        {
            int  totalCount        = 0;
            int  expectedDocuments = 5;
            bool createdDocuments  = false;

            ContainerCore          itemsCore    = this.Container;
            ChangeFeedIteratorCore feedIterator = itemsCore.GetChangeFeedStreamIterator() as ChangeFeedIteratorCore;

            while (feedIterator.HasMoreResults ||
                   (createdDocuments && totalCount == 0))
            {
                using (ResponseMessage responseMessage =
                           await feedIterator.ReadNextAsync(this.cancellationToken))
                {
                    Assert.IsNotNull(feedIterator.FeedToken);
                    if (responseMessage.IsSuccessStatusCode)
                    {
                        Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(responseMessage.Content).Data;
                        totalCount += response.Count;
                    }
                    else
                    {
                        if (!createdDocuments)
                        {
                            await this.CreateRandomItems(this.Container, expectedDocuments, randomPartitionKey : true);

                            createdDocuments = true;
                        }
                    }
                }
            }

            Assert.AreEqual(expectedDocuments, totalCount);
        }
예제 #7
0
        public async Task ChangeFeedIteratorCore_ReadAll()
        {
            int totalCount    = 0;
            int firstRunTotal = 25;
            int batchSize     = 25;

            await this.CreateRandomItems(this.LargerContainer, batchSize, randomPartitionKey : true);

            ContainerInternal      itemsCore    = this.LargerContainer;
            ChangeFeedIteratorCore feedIterator = itemsCore.GetChangeFeedStreamIterator(
                changeFeedRequestOptions:
                new ChangeFeedRequestOptions()
            {
                From = ChangeFeedRequestOptions.StartFrom.CreateFromBeginning(),
            }) as ChangeFeedIteratorCore;
            string continuation = null;

            while (feedIterator.HasMoreResults)
            {
                using (ResponseMessage responseMessage =
                           await feedIterator.ReadNextAsync(this.cancellationToken))
                {
                    if (responseMessage.IsSuccessStatusCode)
                    {
                        Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(responseMessage.Content).Data;
                        totalCount += response.Count;
                    }

                    continuation = responseMessage.ContinuationToken;
                }
            }

            Assert.AreEqual(firstRunTotal, totalCount);

            int expectedFinalCount = 50;

            // Insert another batch of 25 and use the last FeedToken from the first cycle
            await this.CreateRandomItems(this.LargerContainer, batchSize, randomPartitionKey : true);

            ChangeFeedIteratorCore setIteratorNew = itemsCore.GetChangeFeedStreamIterator(
                changeFeedRequestOptions: new ChangeFeedRequestOptions()
            {
                From = ChangeFeedRequestOptions.StartFrom.CreateFromContinuation(continuation),
            }) as ChangeFeedIteratorCore;

            while (setIteratorNew.HasMoreResults)
            {
                using (ResponseMessage responseMessage =
                           await setIteratorNew.ReadNextAsync(this.cancellationToken))
                {
                    if (responseMessage.IsSuccessStatusCode)
                    {
                        Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(responseMessage.Content).Data;
                        totalCount += response.Count;
                    }
                }
            }

            Assert.AreEqual(expectedFinalCount, totalCount);
        }
        public async Task ChangeFeedIteratorCore_WithMaxItemCount()
        {
            ContainerInternal itemsCore = await this.InitializeContainerAsync();

            await this.CreateRandomItems(itemsCore, 2, randomPartitionKey : true);

            ChangeFeedIteratorCore feedIterator = itemsCore.GetChangeFeedStreamIterator(
                ChangeFeedStartFrom.Beginning(),
                ChangeFeedMode.Incremental,
                changeFeedRequestOptions: new ChangeFeedRequestOptions()
            {
                PageSizeHint = 1,
            }) as ChangeFeedIteratorCore;

            while (feedIterator.HasMoreResults)
            {
                using (ResponseMessage responseMessage =
                           await feedIterator.ReadNextAsync(this.cancellationToken))
                {
                    if (!responseMessage.IsSuccessStatusCode)
                    {
                        break;
                    }

                    Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(responseMessage.Content).Data;
                    if (response.Count > 0)
                    {
                        Assert.AreEqual(1, response.Count);
                        return;
                    }
                }
            }

            Assert.Fail("Found no batch with size 1");
        }
예제 #9
0
        public async Task ChangeFeedIteratorCore_ReadNextAsync()
        {
            string          continuation    = "TBD";
            ResponseMessage responseMessage = new ResponseMessage(HttpStatusCode.OK);

            responseMessage.Headers.ETag = continuation;
            responseMessage.Headers[Documents.HttpConstants.HttpHeaders.ItemCount] = "1";

            Mock <CosmosClientContext> cosmosClientContext = new Mock <CosmosClientContext>();

            cosmosClientContext.Setup(c => c.ClientOptions).Returns(new CosmosClientOptions());
            cosmosClientContext
            .Setup(c => c.ProcessResourceOperationStreamAsync(
                       It.IsAny <string>(),
                       It.IsAny <Documents.ResourceType>(),
                       It.IsAny <Documents.OperationType>(),
                       It.IsAny <RequestOptions>(),
                       It.IsAny <ContainerInternal>(),
                       It.IsAny <PartitionKey?>(),
                       It.IsAny <Stream>(),
                       It.IsAny <Action <RequestMessage> >(),
                       It.IsAny <CosmosDiagnosticsContext>(),
                       It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(responseMessage));

            ContainerInternal containerCore = Mock.Of <ContainerInternal>();

            Mock.Get(containerCore)
            .Setup(c => c.ClientContext)
            .Returns(cosmosClientContext.Object);

            FeedRangeInternal range = Mock.Of <FeedRangeInternal>();

            Mock.Get(range)
            .Setup(f => f.Accept(It.IsAny <FeedRangeVisitor>()));
            FeedRangeContinuation feedToken = Mock.Of <FeedRangeContinuation>();

            Mock.Get(feedToken)
            .Setup(f => f.Accept(It.IsAny <FeedRangeVisitor>(), It.IsAny <Action <RequestMessage, string> >()));
            Mock.Get(feedToken)
            .Setup(f => f.FeedRange)
            .Returns(range);
            Mock.Get(feedToken)
            .Setup(f => f.HandleSplitAsync(It.Is <ContainerInternal>(c => c == containerCore), It.IsAny <ResponseMessage>(), It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(Documents.ShouldRetryResult.NoRetry()));
            Mock.Get(feedToken)
            .Setup(f => f.HandleChangeFeedNotModified(It.IsAny <ResponseMessage>()))
            .Returns(Documents.ShouldRetryResult.NoRetry());

            ChangeFeedIteratorCore changeFeedIteratorCore = new ChangeFeedIteratorCore(containerCore, feedToken, null);
            ResponseMessage        response = await changeFeedIteratorCore.ReadNextAsync();

            Mock.Get(feedToken)
            .Verify(f => f.ReplaceContinuation(It.Is <string>(ct => ct == continuation)), Times.Once);

            Mock.Get(feedToken)
            .Verify(f => f.HandleSplitAsync(It.Is <ContainerInternal>(c => c == containerCore), It.IsAny <ResponseMessage>(), It.IsAny <CancellationToken>()), Times.Once);
            Mock.Get(feedToken)
            .Verify(f => f.HandleChangeFeedNotModified(It.IsAny <ResponseMessage>()), Times.Once);
        }
예제 #10
0
        public async Task ChangeFeedIteratorCore_DoesNotUpdateContinuation_OnError()
        {
            string          continuation    = "TBD";
            ResponseMessage responseMessage = new ResponseMessage(HttpStatusCode.Gone);

            responseMessage.Headers.ETag = continuation;

            Mock <CosmosClientContext> cosmosClientContext = new Mock <CosmosClientContext>();

            cosmosClientContext.Setup(c => c.ClientOptions).Returns(new CosmosClientOptions());
            cosmosClientContext
            .Setup(c => c.ProcessResourceOperationStreamAsync(
                       It.IsAny <Uri>(),
                       It.IsAny <Documents.ResourceType>(),
                       It.IsAny <Documents.OperationType>(),
                       It.IsAny <RequestOptions>(),
                       It.IsAny <ContainerInternal>(),
                       It.IsAny <PartitionKey?>(),
                       It.IsAny <Stream>(),
                       It.IsAny <Action <RequestMessage> >(),
                       It.IsAny <CosmosDiagnosticsContext>(),
                       It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(responseMessage));

            ContainerInternal containerCore = Mock.Of <ContainerInternal>();

            Mock.Get(containerCore)
            .Setup(c => c.ClientContext)
            .Returns(cosmosClientContext.Object);
            FeedRangeInternal range = Mock.Of <FeedRangeInternal>();

            Mock.Get(range)
            .Setup(f => f.Accept(It.IsAny <FeedRangeRequestMessagePopulatorVisitor>()));
            FeedRangeContinuation feedToken = Mock.Of <FeedRangeContinuation>();

            Mock.Get(feedToken)
            .Setup(f => f.FeedRange)
            .Returns(range);
            Mock.Get(feedToken)
            .Setup(f => f.HandleSplitAsync(It.Is <ContainerInternal>(c => c == containerCore), It.IsAny <ResponseMessage>(), It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(Documents.ShouldRetryResult.NoRetry()));
            Mock.Get(feedToken)
            .Setup(f => f.HandleChangeFeedNotModified(It.IsAny <ResponseMessage>()))
            .Returns(Documents.ShouldRetryResult.NoRetry());

            ChangeFeedIteratorCore changeFeedIteratorCore = CreateWithCustomFeedToken(containerCore, feedToken);
            ResponseMessage        response = await changeFeedIteratorCore.ReadNextAsync();

            Assert.IsFalse(changeFeedIteratorCore.HasMoreResults);

            Mock.Get(feedToken)
            .Verify(f => f.ReplaceContinuation(It.Is <string>(ct => ct == continuation)), Times.Never);

            Mock.Get(feedToken)
            .Verify(f => f.HandleSplitAsync(It.Is <ContainerInternal>(c => c == containerCore), It.IsAny <ResponseMessage>(), It.IsAny <CancellationToken>()), Times.Once);
            Mock.Get(feedToken)
            .Verify(f => f.HandleChangeFeedNotModified(It.IsAny <ResponseMessage>()), Times.Once);
        }
        public async Task ChangeFeedIteratorCore_HandlesSplitsThroughPipeline()
        {
            int executionCount = 0;
            CosmosClientContext cosmosClientContext = GetMockedClientContext((RequestMessage requestMessage, CancellationToken cancellationToken) =>
            {
                // Force OnBeforeRequestActions call
                requestMessage.ToDocumentServiceRequest();
                if (executionCount++ == 0)
                {
                    return(TestHandler.ReturnStatusCode(HttpStatusCode.Gone, Documents.SubStatusCodes.PartitionKeyRangeGone));
                }

                return(TestHandler.ReturnStatusCode(HttpStatusCode.OK));
            });

            ContainerInternal containerCore = Mock.Of <ContainerInternal>();

            Mock.Get(containerCore)
            .Setup(c => c.ClientContext)
            .Returns(cosmosClientContext);
            Mock.Get(containerCore)
            .Setup(c => c.LinkUri)
            .Returns(new Uri("https://dummy.documents.azure.com:443/dbs"));
            FeedRangeInternal range = Mock.Of <FeedRangeInternal>();

            Mock.Get(range)
            .Setup(f => f.Accept(It.IsAny <FeedRangeVisitor>()));
            FeedRangeContinuation feedToken = Mock.Of <FeedRangeContinuation>();

            Mock.Get(feedToken)
            .Setup(f => f.Accept(It.IsAny <FeedRangeVisitor>(), It.IsAny <Action <RequestMessage, string> >()));
            Mock.Get(feedToken)
            .Setup(f => f.FeedRange)
            .Returns(range);
            Mock.Get(feedToken)
            .Setup(f => f.Accept(It.IsAny <FeedRangeVisitor>(), It.IsAny <Action <RequestMessage, string> >()));
            Mock.Get(feedToken)
            .Setup(f => f.HandleSplitAsync(It.Is <ContainerInternal>(c => c == containerCore), It.IsAny <ResponseMessage>(), It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(Documents.ShouldRetryResult.NoRetry()));
            Mock.Get(feedToken)
            .Setup(f => f.HandleChangeFeedNotModified(It.IsAny <ResponseMessage>()))
            .Returns(Documents.ShouldRetryResult.NoRetry());

            ChangeFeedIteratorCore changeFeedIteratorCore = new ChangeFeedIteratorCore(containerCore, feedToken, null);

            ResponseMessage response = await changeFeedIteratorCore.ReadNextAsync();

            Assert.AreEqual(1, executionCount, "PartitionKeyRangeGoneRetryHandler handled the Split");
            Assert.AreEqual(HttpStatusCode.Gone, response.StatusCode);

            Mock.Get(feedToken)
            .Verify(f => f.ReplaceContinuation(It.IsAny <string>()), Times.Never);

            Mock.Get(feedToken)
            .Verify(f => f.HandleSplitAsync(It.Is <ContainerInternal>(c => c == containerCore), It.IsAny <ResponseMessage>(), It.IsAny <CancellationToken>()), Times.Once);
            Mock.Get(feedToken)
            .Verify(f => f.HandleChangeFeedNotModified(It.IsAny <ResponseMessage>()), Times.Once);
        }
예제 #12
0
        public async Task ChangeFeedIteratorCore_NoFetchNext()
        {
            ContainerInternal itemsCore = await this.InitializeLargeContainerAsync();

            int pkRangesCount = (await itemsCore.ClientContext.DocumentClient.ReadPartitionKeyRangeFeedAsync(itemsCore.LinkUri)).Count;

            int expected   = 25;
            int iterations = 0;

            await this.CreateRandomItems(itemsCore, expected, randomPartitionKey : true);

            string continuation = null;
            int    count        = 0;

            while (true)
            {
                ChangeFeedStartFrom startFrom;
                if (continuation == null)
                {
                    startFrom = ChangeFeedStartFrom.Beginning();
                }
                else
                {
                    startFrom = ChangeFeedStartFrom.ContinuationToken(continuation);
                }

                ChangeFeedIteratorCore feedIterator = itemsCore.GetChangeFeedStreamIterator(startFrom, ChangeFeedMode.Incremental) as ChangeFeedIteratorCore;
                using (ResponseMessage responseMessage = await feedIterator.ReadNextAsync(this.cancellationToken))
                {
                    if (responseMessage.IsSuccessStatusCode)
                    {
                        Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(responseMessage.Content).Data;
                        count += response.Count;
                    }
                    else
                    {
                        if (responseMessage.StatusCode != HttpStatusCode.NotModified)
                        {
                            Assert.Fail(responseMessage.ErrorMessage);
                        }
                    }

                    continuation = responseMessage.ContinuationToken;
                }

                if (count.Equals(expected))
                {
                    break;
                }

                if (iterations++ > pkRangesCount)
                {
                    Assert.Fail("" +
                                "Feed does not contain all elements even after looping through PK ranges. " +
                                "Either the continuation is not moving forward or there is some state problem.");
                }
            }
        }
        public async Task ChangeFeedIteratorCore_ReadAll()
        {
            int totalCount    = 0;
            int firstRunTotal = 25;
            int batchSize     = 25;

            await this.CreateRandomItems(this.Container, batchSize, randomPartitionKey : true);

            ContainerCore          itemsCore    = this.Container;
            ChangeFeedIteratorCore feedIterator = itemsCore.GetChangeFeedStreamIterator(changeFeedRequestOptions: new ChangeFeedRequestOptions()
            {
                StartTime = DateTime.MinValue.ToUniversalTime()
            }) as ChangeFeedIteratorCore;

            while (feedIterator.HasMoreResults)
            {
                using (ResponseMessage responseMessage =
                           await feedIterator.ReadNextAsync(this.cancellationToken))
                {
                    Assert.IsNotNull(feedIterator.FeedToken);

                    if (responseMessage.IsSuccessStatusCode)
                    {
                        Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(responseMessage.Content).Data;
                        totalCount += response.Count;
                    }
                }
            }

            Assert.AreEqual(firstRunTotal, totalCount);

            int expectedFinalCount = 50;

            // Insert another batch of 25 and use the last FeedToken from the first cycle
            await this.CreateRandomItems(this.Container, batchSize, randomPartitionKey : true);

            ChangeFeedIteratorCore setIteratorNew = itemsCore.GetChangeFeedStreamIterator(feedToken: feedIterator.FeedToken, changeFeedRequestOptions: new ChangeFeedRequestOptions()
            {
                StartTime = DateTime.MinValue.ToUniversalTime()
            }) as ChangeFeedIteratorCore;

            while (setIteratorNew.HasMoreResults)
            {
                using (ResponseMessage responseMessage =
                           await setIteratorNew.ReadNextAsync(this.cancellationToken))
                {
                    Assert.IsNotNull(setIteratorNew.FeedToken);
                    if (responseMessage.IsSuccessStatusCode)
                    {
                        Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(responseMessage.Content).Data;
                        totalCount += response.Count;
                    }
                }
            }

            Assert.AreEqual(expectedFinalCount, totalCount);
        }
        public async Task ChangeFeedIteratorCore_Retries()
        {
            string          continuation    = "TBD";
            ResponseMessage responseMessage = new ResponseMessage(HttpStatusCode.OK);

            responseMessage.Headers.ETag = continuation;

            Mock <CosmosClientContext> cosmosClientContext = new Mock <CosmosClientContext>();

            cosmosClientContext.Setup(c => c.ClientOptions).Returns(new CosmosClientOptions());
            cosmosClientContext
            .Setup(c => c.ProcessResourceOperationStreamAsync(
                       It.IsAny <Uri>(),
                       It.IsAny <Documents.ResourceType>(),
                       It.IsAny <Documents.OperationType>(),
                       It.IsAny <RequestOptions>(),
                       It.IsAny <ContainerCore>(),
                       It.IsAny <PartitionKey?>(),
                       It.IsAny <Stream>(),
                       It.IsAny <Action <RequestMessage> >(),
                       It.IsAny <CosmosDiagnosticsContext>(),
                       It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(responseMessage));

            ContainerCore     containerCore = Mock.Of <ContainerCore>();
            FeedTokenInternal feedToken     = Mock.Of <FeedTokenInternal>();

            Mock.Get(feedToken)
            .Setup(f => f.EnrichRequest(It.IsAny <RequestMessage>()));
            Mock.Get(feedToken)
            .SetupSequence(f => f.ShouldRetryAsync(It.Is <ContainerCore>(c => c == containerCore), It.IsAny <ResponseMessage>(), It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(true))
            .Returns(Task.FromResult(false));

            ChangeFeedIteratorCore changeFeedIteratorCore = new ChangeFeedIteratorCore(cosmosClientContext.Object, containerCore, feedToken, null);
            ResponseMessage        response = await changeFeedIteratorCore.ReadNextAsync();

            Mock.Get(feedToken)
            .Verify(f => f.UpdateContinuation(It.IsAny <string>()), Times.Exactly(2));

            Mock.Get(feedToken)
            .Verify(f => f.ShouldRetryAsync(It.Is <ContainerCore>(c => c == containerCore), It.IsAny <ResponseMessage>(), It.IsAny <CancellationToken>()), Times.Exactly(2));

            Mock.Get(cosmosClientContext.Object)
            .Verify(c => c.ProcessResourceOperationStreamAsync(
                        It.IsAny <Uri>(),
                        It.IsAny <Documents.ResourceType>(),
                        It.IsAny <Documents.OperationType>(),
                        It.IsAny <RequestOptions>(),
                        It.IsAny <ContainerCore>(),
                        It.IsAny <PartitionKey?>(),
                        It.IsAny <Stream>(),
                        It.IsAny <Action <RequestMessage> >(),
                        It.IsAny <CosmosDiagnosticsContext>(),
                        It.IsAny <CancellationToken>()), Times.Exactly(2));
        }
        public async Task ChangeFeedIteratorCore_UpdatesContinuation_On304()
        {
            IDocumentContainer documentContainer = await CreateDocumentContainerAsync(numItems : 0);

            ChangeFeedIteratorCore changeFeedIteratorCore = new ChangeFeedIteratorCore(
                documentContainer,
                new ChangeFeedRequestOptions(),
                ChangeFeedStartFrom.Beginning());

            ResponseMessage responseMessage = await changeFeedIteratorCore.ReadNextAsync();

            Assert.AreEqual(HttpStatusCode.NotModified, responseMessage.StatusCode);
            string continuationToken = responseMessage.Headers.ContinuationToken;

            ResponseMessage responseMessage2 = await changeFeedIteratorCore.ReadNextAsync();

            Assert.AreEqual(HttpStatusCode.NotModified, responseMessage.StatusCode);
            string continuationToken2 = responseMessage2.Headers.ContinuationToken;

            Assert.AreNotEqual(continuationToken, continuationToken2);
        }
예제 #16
0
        public async Task ChangeFeedBaselineAsync()
        {
            ChangeFeedIteratorCore feedIterator = ((ContainerCore)this.container)
                                                  .GetChangeFeedStreamIterator(
                ChangeFeedStartFrom.Beginning()) as ChangeFeedIteratorCore;

            while (feedIterator.HasMoreResults)
            {
                using (ResponseMessage responseMessage = await feedIterator.ReadNextAsync())
                {
                }
            }
        }
        public async Task ChangeFeedIteratorCore_PartitionKeyRangeId_ReadAll()
        {
            int totalDocuments = 200;

            await this.CreateRandomItems(this.LargerContainer, totalDocuments, randomPartitionKey : true);

            DocumentFeedResponse <Documents.PartitionKeyRange> ranges = await this.LargerContainer.ClientContext.DocumentClient.ReadPartitionKeyRangeFeedAsync(this.LargerContainer.LinkUri);

            List <FeedToken> tokens = new List <FeedToken>(ranges.Count);

            foreach (Documents.PartitionKeyRange range in ranges)
            {
                tokens.Add(new FeedTokenPartitionKeyRange(range.Id));
            }

            ContainerCore      itemsCore = this.LargerContainer;
            List <Task <int> > tasks     = tokens.Select(token => Task.Run(async() =>
            {
                int count = 0;
                ChangeFeedIteratorCore iteratorForToken =
                    itemsCore.GetChangeFeedStreamIterator(token, changeFeedRequestOptions: new ChangeFeedRequestOptions()
                {
                    StartTime = DateTime.MinValue.ToUniversalTime()
                }) as ChangeFeedIteratorCore;
                while (iteratorForToken.HasMoreResults)
                {
                    using (ResponseMessage responseMessage =
                               await iteratorForToken.ReadNextAsync(this.cancellationToken))
                    {
                        if (responseMessage.Content != null)
                        {
                            Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(responseMessage.Content).Data;
                            count += response.Count;
                        }
                    }
                }

                return(count);
            })).ToList();

            await Task.WhenAll(tasks);

            int documentsRead = 0;

            foreach (Task <int> task in tasks)
            {
                documentsRead += task.Result;
            }

            Assert.AreEqual(totalDocuments, documentsRead);
        }
예제 #18
0
        public async Task GetFeedRangesAsync_AllowsParallelProcessing()
        {
            ContainerInternal itemsCore = await this.InitializeLargeContainerAsync();

            int pkRangesCount = (await itemsCore.ClientContext.DocumentClient.ReadPartitionKeyRangeFeedAsync(itemsCore.LinkUri)).Count;

            IEnumerable <FeedRange> tokens = await itemsCore.GetFeedRangesAsync();

            Assert.IsTrue(pkRangesCount > 1, "Should have created a multi partition container.");
            Assert.AreEqual(pkRangesCount, tokens.Count());
            int totalDocuments = 200;

            await this.CreateRandomItems(itemsCore, totalDocuments, randomPartitionKey : true);

            List <Task <int> > tasks = tokens.Select(token => Task.Run(async() =>
            {
                int count = 0;
                ChangeFeedIteratorCore iteratorForToken =
                    itemsCore.GetChangeFeedStreamIterator(
                        ChangeFeedStartFrom.Beginning(token),
                        ChangeFeedMode.Incremental) as ChangeFeedIteratorCore;
                while (true)
                {
                    using (ResponseMessage responseMessage =
                               await iteratorForToken.ReadNextAsync(this.cancellationToken))
                    {
                        if (!responseMessage.IsSuccessStatusCode)
                        {
                            break;
                        }

                        Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(responseMessage.Content).Data;
                        count += response.Count;
                    }
                }

                return(count);
            })).ToList();

            await Task.WhenAll(tasks);

            int documentsRead = 0;

            foreach (Task <int> task in tasks)
            {
                documentsRead += task.Result;
            }

            Assert.AreEqual(totalDocuments, documentsRead);
        }
예제 #19
0
        public async Task ChangeFeedBaselineAsync()
        {
            ChangeFeedIteratorCore feedIterator = ((ContainerCore)this.container)
                                                  .GetChangeFeedStreamIterator(
                changeFeedRequestOptions: new ChangeFeedRequestOptions()
            {
                From = ChangeFeedRequestOptions.StartFrom.CreateFromBeginning(),
            }) as ChangeFeedIteratorCore;

            while (feedIterator.HasMoreResults)
            {
                using (ResponseMessage responseMessage = await feedIterator.ReadNextAsync())
                {
                }
            }
        }
예제 #20
0
        public async Task ChangeFeedBaselineAsync()
        {
            ChangeFeedIteratorCore feedIterator = ((ContainerCore)this.container)
                                                  .GetChangeFeedStreamIterator(
                changeFeedRequestOptions: new ChangeFeedRequestOptions()
            {
                StartTime = DateTime.MinValue.ToUniversalTime()
            }) as ChangeFeedIteratorCore;

            while (feedIterator.HasMoreResults)
            {
                using (ResponseMessage responseMessage = await feedIterator.ReadNextAsync())
                {
                }
            }
        }
예제 #21
0
        public async Task ChangeFeedIteratorCore_BreathFirst()
        {
            int               expected      = 500;
            CosmosObject      previousToken = null;
            ContainerInternal itemsCore     = await this.InitializeLargeContainerAsync();

            await this.CreateRandomItems(itemsCore, expected, randomPartitionKey : true);

            ChangeFeedIteratorCore feedIterator = itemsCore.GetChangeFeedStreamIterator(
                ChangeFeedStartFrom.Beginning(),
                ChangeFeedMode.Incremental,
                new ChangeFeedRequestOptions()
            {
                PageSizeHint = 1,
            }) as ChangeFeedIteratorCore;

            while (true)
            {
                using (ResponseMessage responseMessage = await feedIterator.ReadNextAsync(this.cancellationToken))
                {
                    CosmosObject cosmosObject = CosmosObject.Parse(responseMessage.ContinuationToken);
                    if (!cosmosObject.TryGetValue("Continuation", out CosmosArray cosmosArray))
                    {
                        Assert.Fail();
                        throw new Exception();
                    }

                    CosmosObject currentToken = (CosmosObject)cosmosArray[0];

                    if (previousToken != null)
                    {
                        // Verify that the token, even though it yielded results, it moved to a new range
                        Assert.AreNotEqual(previousToken, currentToken);
                        break;
                    }

                    previousToken = currentToken;

                    if (responseMessage.StatusCode == HttpStatusCode.NotModified)
                    {
                        break;
                    }
                }
            }
        }
        //[Timeout(30000)]
        public async Task ChangeFeedIteratorCore_NoFetchNext()
        {
            int pkRangesCount = (await this.LargerContainer.ClientContext.DocumentClient.ReadPartitionKeyRangeFeedAsync(this.LargerContainer.LinkUri)).Count;

            int expected   = 25;
            int iterations = 0;

            await this.CreateRandomItems(this.LargerContainer, expected, randomPartitionKey : true);

            ContainerCore itemsCore = this.LargerContainer;
            FeedToken     feedToken = null;
            int           count     = 0;

            while (true)
            {
                ChangeFeedRequestOptions requestOptions = new ChangeFeedRequestOptions()
                {
                    StartTime = DateTime.MinValue.ToUniversalTime()
                };

                ChangeFeedIteratorCore feedIterator = feedToken == null?itemsCore.GetChangeFeedStreamIterator(changeFeedRequestOptions : requestOptions) as ChangeFeedIteratorCore
                                                      : itemsCore.GetChangeFeedStreamIterator(feedToken, changeFeedRequestOptions: requestOptions) as ChangeFeedIteratorCore;

                using (ResponseMessage responseMessage =
                           await feedIterator.ReadNextAsync(this.cancellationToken))
                {
                    feedToken = feedIterator.FeedToken;
                    if (responseMessage.IsSuccessStatusCode)
                    {
                        Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(responseMessage.Content).Data;
                        count += response.Count;
                    }
                }

                if (count.Equals(expected))
                {
                    break;
                }

                if (iterations++ > pkRangesCount)
                {
                    Assert.Fail("Feed does not contain all elements even after looping through PK ranges. Either the continuation is not moving forward or there is some state problem.");
                }
            }
        }
예제 #23
0
        public async Task ChangeFeedIteratorCore_DoesNotUpdateContinuation_OnError()
        {
            int numItems = 100;
            IDocumentContainer documentContainer = await CreateDocumentContainerAsync(
                numItems,
                failureConfigs : new FlakyDocumentContainer.FailureConfigs(inject429s: true, injectEmptyPages: true));

            ChangeFeedIteratorCore changeFeedIteratorCore = new ChangeFeedIteratorCore(
                documentContainer,
                ChangeFeedMode.Incremental,
                new ChangeFeedRequestOptions(),
                ChangeFeedStartFrom.Beginning(),
                this.MockClientContext());

            int count         = 0;
            int numIterations = 500;

            while (numIterations-- > 0)
            {
                ResponseMessage responseMessage = await changeFeedIteratorCore.ReadNextAsync();

                if (!(responseMessage.IsSuccessStatusCode || responseMessage.StatusCode == HttpStatusCode.NotModified))
                {
                    if (responseMessage.Headers.ContinuationToken != null)
                    {
                        Assert.Fail();
                    }
                }
                else
                {
                    if (responseMessage.StatusCode != HttpStatusCode.NotModified)
                    {
                        count += GetChanges(responseMessage.Content).Count;
                    }
                }

                if (count > numItems)
                {
                    Assert.Fail();
                }
            }

            Assert.AreEqual(numItems, count);
        }
예제 #24
0
        public async Task ChangeFeedIteratorCore_PartitionKey_ReadAll()
        {
            int totalCount    = 0;
            int firstRunTotal = 25;
            int batchSize     = 25;

            string pkToRead = "pkToRead";
            string otherPK  = "otherPK";

            ContainerInternal itemsCore = await this.InitializeContainerAsync();

            for (int i = 0; i < batchSize; i++)
            {
                await itemsCore.CreateItemAsync(ToDoActivity.CreateRandomToDoActivity(pk: pkToRead));
            }

            for (int i = 0; i < batchSize; i++)
            {
                await itemsCore.CreateItemAsync(ToDoActivity.CreateRandomToDoActivity(pk: otherPK));
            }

            ChangeFeedIteratorCore feedIterator = itemsCore.GetChangeFeedStreamIterator(
                ChangeFeedStartFrom.Beginning(
                    FeedRange.FromPartitionKey(
                        new PartitionKey(pkToRead))),
                ChangeFeedMode.Incremental,
                new ChangeFeedRequestOptions()
            {
                PageSizeHint = 1,
            }) as ChangeFeedIteratorCore;
            string continuation = null;

            while (feedIterator.HasMoreResults)
            {
                using (ResponseMessage responseMessage =
                           await feedIterator.ReadNextAsync(this.cancellationToken))
                {
                    if (!responseMessage.IsSuccessStatusCode)
                    {
                        continuation = responseMessage.ContinuationToken;
                        break;
                    }

                    Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(responseMessage.Content).Data;
                    totalCount += response.Count;
                    foreach (ToDoActivity toDoActivity in response)
                    {
                        Assert.AreEqual(pkToRead, toDoActivity.pk);
                    }
                }
            }

            Assert.AreEqual(firstRunTotal, totalCount);

            int expectedFinalCount = 50;

            // Insert another batch of 25 and use the last FeedToken from the first cycle
            for (int i = 0; i < batchSize; i++)
            {
                await itemsCore.CreateItemAsync(ToDoActivity.CreateRandomToDoActivity(pk: pkToRead));
            }

            ChangeFeedIteratorCore setIteratorNew = itemsCore.GetChangeFeedStreamIterator(
                ChangeFeedStartFrom.ContinuationToken(continuation),
                ChangeFeedMode.Incremental) as ChangeFeedIteratorCore;

            while (setIteratorNew.HasMoreResults)
            {
                using (ResponseMessage responseMessage =
                           await setIteratorNew.ReadNextAsync(this.cancellationToken))
                {
                    if (!responseMessage.IsSuccessStatusCode)
                    {
                        break;
                    }

                    Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(responseMessage.Content).Data;
                    totalCount += response.Count;
                    foreach (ToDoActivity toDoActivity in response)
                    {
                        Assert.AreEqual(pkToRead, toDoActivity.pk);
                    }
                }
            }

            Assert.AreEqual(expectedFinalCount, totalCount);
        }
예제 #25
0
        public async Task ChangeFeed_FeedRange_FromV2SDK()
        {
            ContainerResponse largerContainer = await this.database.CreateContainerAsync(
                new ContainerProperties(id : Guid.NewGuid().ToString(), partitionKeyPath : "/status"),
                throughput : 20000,
                cancellationToken : this.cancellationToken);

            ContainerCore container = (ContainerInlineCore)largerContainer;

            int expected = 100;
            int count    = 0;

            await this.CreateRandomItems(container, expected, randomPartitionKey : true);

            IReadOnlyList <FeedRange> feedRanges = await container.GetFeedRangesAsync();

            List <string> continuations = new List <string>();

            // First do one request to construct the old model information based on Etag
            foreach (FeedRange feedRange in feedRanges)
            {
                IEnumerable <string> pkRangeIds = await container.GetPartitionKeyRangesAsync(feedRange);

                ChangeFeedRequestOptions requestOptions = new ChangeFeedRequestOptions()
                {
                    StartTime = DateTime.MinValue.ToUniversalTime(), MaxItemCount = 1
                };
                ChangeFeedIteratorCore feedIterator  = container.GetChangeFeedStreamIterator(feedRange: feedRange, changeFeedRequestOptions: requestOptions) as ChangeFeedIteratorCore;
                ResponseMessage        firstResponse = await feedIterator.ReadNextAsync();

                if (firstResponse.IsSuccessStatusCode)
                {
                    Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(firstResponse.Content).Data;
                    count += response.Count;
                }

                // Construct the continuation's range, using PKRangeId + ETag
                List <dynamic> ct = new List <dynamic>()
                {
                    new { min = string.Empty, max = string.Empty, token = firstResponse.Headers.ETag }
                };
                // Extract Etag and manually construct the continuation
                dynamic oldContinuation = new { V = 0, PKRangeId = pkRangeIds.First(), Continuation = ct };
                continuations.Add(JsonConvert.SerializeObject(oldContinuation));
            }

            // Now start the new iterators with the constructed continuations from migration
            foreach (string continuation in continuations)
            {
                ChangeFeedRequestOptions requestOptions = new ChangeFeedRequestOptions()
                {
                    MaxItemCount = 100
                };
                ChangeFeedIteratorCore feedIterator  = container.GetChangeFeedStreamIterator(continuationToken: continuation, changeFeedRequestOptions: requestOptions) as ChangeFeedIteratorCore;
                ResponseMessage        firstResponse = await feedIterator.ReadNextAsync();

                if (firstResponse.IsSuccessStatusCode)
                {
                    Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(firstResponse.Content).Data;
                    count += response.Count;
                }
            }

            Assert.AreEqual(expected, count);
        }
예제 #26
0
        public async Task ChangeFeedIteratorCore_FromV2SDK()
        {
            int expected = 100;
            int count    = 0;

            await this.CreateRandomItems(this.LargerContainer, expected, randomPartitionKey : true);

            IReadOnlyList <FeedRange> feedRanges = await this.LargerContainer.GetFeedRangesAsync();

            List <string> continuations = new List <string>();

            // First do one request to construct the old model information based on Etag
            foreach (FeedRange feedRange in feedRanges)
            {
                ChangeFeedRequestOptions requestOptions = new ChangeFeedRequestOptions()
                {
                    StartTime = DateTime.MinValue.ToUniversalTime(), MaxItemCount = 1
                };
                ChangeFeedIteratorCore feedIterator  = this.LargerContainer.GetChangeFeedStreamIterator(feedRange: feedRange, changeFeedRequestOptions: requestOptions) as ChangeFeedIteratorCore;
                ResponseMessage        firstResponse = await feedIterator.ReadNextAsync();

                if (firstResponse.IsSuccessStatusCode)
                {
                    Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(firstResponse.Content).Data;
                    count += response.Count;
                }

                // Construct the continuation's range, FeedRange.ToString() = [min,max)
                string         range     = feedRange.ToString();
                int            separator = range.IndexOf(',');
                string         min       = range.Substring(1, separator - 1);
                string         max       = range.Substring(separator + 1, range.IndexOf(')') - separator - 1);
                dynamic        ctRange   = new { min = min, max = max };
                List <dynamic> ct        = new List <dynamic>()
                {
                    new { min = min, max = max, token = firstResponse.Headers.ETag, range = ctRange }
                };
                // Extract Etag and manually construct the continuation
                dynamic oldContinuation = new { V = 0, Range = ctRange, Continuation = ct };
                continuations.Add(JsonConvert.SerializeObject(oldContinuation));
            }

            // Now start the new iterators with the constructed continuations from migration
            foreach (string continuation in continuations)
            {
                ChangeFeedRequestOptions requestOptions = new ChangeFeedRequestOptions()
                {
                    MaxItemCount = 100
                };
                ChangeFeedIteratorCore feedIterator  = this.LargerContainer.GetChangeFeedStreamIterator(continuationToken: continuation, changeFeedRequestOptions: requestOptions) as ChangeFeedIteratorCore;
                ResponseMessage        firstResponse = await feedIterator.ReadNextAsync();

                if (firstResponse.IsSuccessStatusCode)
                {
                    Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(firstResponse.Content).Data;
                    count += response.Count;
                }
            }

            Assert.AreEqual(expected, count);
        }
예제 #27
0
        public async Task ChangeFeedIteratorCore_PartitionKey_ReadAll()
        {
            int totalCount    = 0;
            int firstRunTotal = 25;
            int batchSize     = 25;

            string pkToRead = "pkToRead";
            string otherPK  = "otherPK";

            for (int i = 0; i < batchSize; i++)
            {
                await this.Container.CreateItemAsync(this.CreateRandomToDoActivity(pkToRead));
            }

            for (int i = 0; i < batchSize; i++)
            {
                await this.Container.CreateItemAsync(this.CreateRandomToDoActivity(otherPK));
            }

            ContainerCore          itemsCore    = this.Container;
            ChangeFeedIteratorCore feedIterator = itemsCore.GetChangeFeedStreamIterator(new PartitionKey(pkToRead), changeFeedRequestOptions: new ChangeFeedRequestOptions()
            {
                StartTime = DateTime.MinValue.ToUniversalTime()
            }) as ChangeFeedIteratorCore;
            string continuation = null;

            while (feedIterator.HasMoreResults)
            {
                using (ResponseMessage responseMessage =
                           await feedIterator.ReadNextAsync(this.cancellationToken))
                {
                    if (responseMessage.IsSuccessStatusCode)
                    {
                        Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(responseMessage.Content).Data;
                        totalCount += response.Count;
                        foreach (ToDoActivity toDoActivity in response)
                        {
                            Assert.AreEqual(pkToRead, toDoActivity.status);
                        }
                    }

                    continuation = responseMessage.ContinuationToken;
                }
            }

            Assert.AreEqual(firstRunTotal, totalCount);

            int expectedFinalCount = 50;

            // Insert another batch of 25 and use the last FeedToken from the first cycle
            for (int i = 0; i < batchSize; i++)
            {
                await this.Container.CreateItemAsync(this.CreateRandomToDoActivity(pkToRead));
            }

            ChangeFeedIteratorCore setIteratorNew = itemsCore.GetChangeFeedStreamIterator(continuationToken: continuation, changeFeedRequestOptions: new ChangeFeedRequestOptions()
            {
                StartTime = DateTime.MinValue.ToUniversalTime()
            }) as ChangeFeedIteratorCore;

            while (setIteratorNew.HasMoreResults)
            {
                using (ResponseMessage responseMessage =
                           await setIteratorNew.ReadNextAsync(this.cancellationToken))
                {
                    if (responseMessage.IsSuccessStatusCode)
                    {
                        Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(responseMessage.Content).Data;
                        totalCount += response.Count;
                        foreach (ToDoActivity toDoActivity in response)
                        {
                            Assert.AreEqual(pkToRead, toDoActivity.status);
                        }
                    }
                }
            }

            Assert.AreEqual(expectedFinalCount, totalCount);
        }
예제 #28
0
        public async Task ChangeFeed_FeedRange_FromV0Token()
        {
            ContainerResponse largerContainer = await this.database.CreateContainerAsync(
                new ContainerProperties(id : Guid.NewGuid().ToString(), partitionKeyPath : "/pk"),
                throughput : 20000,
                cancellationToken : this.cancellationToken);

            ContainerInternal container = (ContainerInlineCore)largerContainer;

            int expected = 100;
            int count    = 0;

            await this.CreateRandomItems((ContainerCore)container, expected, randomPartitionKey : true);

            IReadOnlyList <FeedRange> feedRanges = await container.GetFeedRangesAsync();

            List <string> continuations = new List <string>();

            // First do one request to construct the old model information based on Etag
            foreach (FeedRange feedRange in feedRanges)
            {
                IEnumerable <string> pkRangeIds = await container.GetPartitionKeyRangesAsync(feedRange);

                ChangeFeedRequestOptions requestOptions = new ChangeFeedRequestOptions()
                {
                    PageSizeHint = 1
                };
                ChangeFeedIteratorCore feedIterator = container.GetChangeFeedStreamIterator(
                    changeFeedStartFrom: ChangeFeedStartFrom.Beginning(feedRange),
                    changeFeedMode: ChangeFeedMode.Incremental,
                    changeFeedRequestOptions: requestOptions) as ChangeFeedIteratorCore;
                ResponseMessage firstResponse = await feedIterator.ReadNextAsync();

                // Construct the continuation's range, using PKRangeId + ETag
                List <dynamic> ct = new List <dynamic>()
                {
                    new
                    {
                        FeedRange = new
                        {
                            type  = "Physical Partition Key Range Id",
                            value = pkRangeIds.First()
                        },
                        State = new
                        {
                            type  = "continuation",
                            value = JObject.Parse(firstResponse.ContinuationToken)["Continuation"][0]["State"]["value"].ToString()
                        }
                    }
                };

                if (firstResponse.Content != null)
                {
                    Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(firstResponse.Content).Data;
                    count += response.Count;
                }

                // Extract Etag and manually construct the continuation
                dynamic oldContinuation = new
                {
                    V            = 2,
                    Rid          = await container.GetCachedRIDAsync(cancellationToken : this.cancellationToken),
                    Continuation = ct
                };
                continuations.Add(JsonConvert.SerializeObject(oldContinuation));
            }

            // Now start the new iterators with the constructed continuations from migration
            foreach (string continuation in continuations)
            {
                ChangeFeedRequestOptions requestOptions = new ChangeFeedRequestOptions()
                {
                    PageSizeHint = 100,
                };
                ChangeFeedIteratorCore feedIterator = container.GetChangeFeedStreamIterator(
                    changeFeedStartFrom: ChangeFeedStartFrom.ContinuationToken(continuation),
                    changeFeedMode: ChangeFeedMode.Incremental,
                    changeFeedRequestOptions: requestOptions) as ChangeFeedIteratorCore;
                ResponseMessage firstResponse = await feedIterator.ReadNextAsync();

                if (firstResponse.IsSuccessStatusCode)
                {
                    Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(firstResponse.Content).Data;
                    count += response.Count;
                    string migratedContinuation = firstResponse.ContinuationToken;
                    TryCatch <CosmosElement> monadicParsedToken = CosmosElement.Monadic.Parse(migratedContinuation);
                    Assert.IsFalse(monadicParsedToken.Failed);
                    TryCatch <VersionedAndRidCheckedCompositeToken> monadicVersionedToken = VersionedAndRidCheckedCompositeToken
                                                                                            .MonadicCreateFromCosmosElement(monadicParsedToken.Result);
                    Assert.IsFalse(monadicVersionedToken.Failed);
                    VersionedAndRidCheckedCompositeToken versionedAndRidCheckedCompositeToken = monadicVersionedToken.Result;
                    Assert.AreEqual(VersionedAndRidCheckedCompositeToken.Version.V2, versionedAndRidCheckedCompositeToken.VersionNumber);
                }
            }

            Assert.AreEqual(expected, count);
        }
예제 #29
0
        public async Task ChangeFeed_FeedRange_FromV0Token()
        {
            ContainerResponse largerContainer = await this.database.CreateContainerAsync(
                new ContainerProperties(id : Guid.NewGuid().ToString(), partitionKeyPath : "/status"),
                throughput : 20000,
                cancellationToken : this.cancellationToken);

            ContainerInternal container = (ContainerInlineCore)largerContainer;

            int expected = 100;
            int count    = 0;

            await this.CreateRandomItems((ContainerCore)container, expected, randomPartitionKey : true);

            IReadOnlyList <FeedRange> feedRanges = await container.GetFeedRangesAsync();

            List <string> continuations = new List <string>();

            // First do one request to construct the old model information based on Etag
            foreach (FeedRange feedRange in feedRanges)
            {
                IEnumerable <string> pkRangeIds = await container.GetPartitionKeyRangesAsync(feedRange);

                ChangeFeedRequestOptions requestOptions = new ChangeFeedRequestOptions()
                {
                    PageSizeHint = 1
                };
                ChangeFeedIteratorCore feedIterator = container.GetChangeFeedStreamIterator(
                    changeFeedStartFrom: ChangeFeedStartFrom.Beginning(feedRange),
                    changeFeedRequestOptions: requestOptions) as ChangeFeedIteratorCore;
                ResponseMessage firstResponse = await feedIterator.ReadNextAsync();

                FeedRangeEpk FeedRangeEpk = feedRange as FeedRangeEpk;

                // Construct the continuation's range, using PKRangeId + ETag
                List <dynamic> ct = new List <dynamic>()
                {
                    new
                    {
                        min   = FeedRangeEpk.Range.Min,
                        max   = FeedRangeEpk.Range.Max,
                        token = (string)null
                    }
                };

                // Extract Etag and manually construct the continuation
                dynamic oldContinuation = new
                {
                    V            = 0,
                    Rid          = await container.GetCachedRIDAsync(cancellationToken : this.cancellationToken),
                    Continuation = ct
                };
                continuations.Add(JsonConvert.SerializeObject(oldContinuation));
            }

            // Now start the new iterators with the constructed continuations from migration
            foreach (string continuation in continuations)
            {
                ChangeFeedRequestOptions requestOptions = new ChangeFeedRequestOptions()
                {
                    PageSizeHint             = 100,
                    EmitOldContinuationToken = true,
                };
                ChangeFeedIteratorCore feedIterator = container.GetChangeFeedStreamIterator(
                    changeFeedStartFrom: ChangeFeedStartFrom.ContinuationToken(continuation),
                    changeFeedRequestOptions: requestOptions) as ChangeFeedIteratorCore;
                ResponseMessage firstResponse = await feedIterator.ReadNextAsync();

                if (firstResponse.IsSuccessStatusCode)
                {
                    Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(firstResponse.Content).Data;
                    count += response.Count;
                    string migratedContinuation = firstResponse.ContinuationToken;
                    Assert.IsTrue(FeedRangeContinuation.TryParse(migratedContinuation, out FeedRangeContinuation feedRangeContinuation));
                    Assert.IsTrue(feedRangeContinuation.FeedRange is FeedRangeEpk);
                }
            }

            Assert.AreEqual(expected, count);
        }
예제 #30
0
        public async Task TestCancellationTokenAsync()
        {
            CancellationTokenRequestHandler cancellationTokenHandler = new CancellationTokenRequestHandler();

            ContainerInternal itemsCore = await this.InitializeContainerAsync();

            await this.CreateRandomItems(itemsCore, 100, randomPartitionKey : true);

            // Inject validating handler
            RequestHandler currentInnerHandler = this.cosmosClient.RequestHandler.InnerHandler;

            this.cosmosClient.RequestHandler.InnerHandler = cancellationTokenHandler;
            cancellationTokenHandler.InnerHandler         = currentInnerHandler;

            {
                // Test to see if the token flows to the pipeline
                CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
                ChangeFeedIteratorCore  feedIterator            = itemsCore.GetChangeFeedStreamIterator(
                    ChangeFeedStartFrom.Beginning(),
                    ChangeFeedMode.Incremental) as ChangeFeedIteratorCore;
                await feedIterator.ReadNextAsync(cancellationTokenSource.Token);

                Assert.AreEqual(cancellationTokenSource.Token, cancellationTokenHandler.LastUsedToken, "The token passed did not reach the pipeline");
            }

            // See if cancellation token is honored for first request
            try
            {
                CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
                cancellationTokenSource.Cancel();
                ChangeFeedIteratorCore feedIterator = itemsCore.GetChangeFeedStreamIterator(
                    ChangeFeedStartFrom.Beginning(),
                    ChangeFeedMode.Incremental) as ChangeFeedIteratorCore;
                await feedIterator.ReadNextAsync(cancellationTokenSource.Token);

                Assert.Fail("Expected exception.");
            }
            catch (OperationCanceledException)
            {
            }

            // See if cancellation token is honored for second request
            try
            {
                CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
                cancellationTokenSource.Cancel();
                ChangeFeedIteratorCore feedIterator = itemsCore.GetChangeFeedStreamIterator(
                    ChangeFeedStartFrom.Beginning(),
                    ChangeFeedMode.Incremental) as ChangeFeedIteratorCore;
                await feedIterator.ReadNextAsync();

                await feedIterator.ReadNextAsync(cancellationTokenSource.Token);

                Assert.Fail("Expected exception.");
            }
            catch (OperationCanceledException)
            {
            }

            // See if cancellation token is honored mid draining
            try
            {
                CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
                ChangeFeedIteratorCore  feedIterator            = itemsCore.GetChangeFeedStreamIterator(
                    ChangeFeedStartFrom.Beginning(),
                    ChangeFeedMode.Incremental) as ChangeFeedIteratorCore;
                await feedIterator.ReadNextAsync(cancellationTokenSource.Token);

                cancellationTokenSource.Cancel();
                await feedIterator.ReadNextAsync(cancellationTokenSource.Token);

                Assert.Fail("Expected exception.");
            }
            catch (OperationCanceledException)
            {
            }
        }