public async Task TestIteratorContract()
        {
            this.ContinuationToken     = null;
            this.Options               = new QueryRequestOptions();
            this.CancellationToken     = new CancellationTokenSource().Token;
            this.ContinueNextExecution = true;

            FeedIterator resultSetIterator = new FeedIteratorCore(
                this.MaxItemCount,
                this.ContinuationToken,
                this.Options,
                this.NextResultSetDelegate);

            Assert.IsTrue(resultSetIterator.HasMoreResults);

            ResponseMessage response = await resultSetIterator.ReadNextAsync(this.CancellationToken);

            this.ContinuationToken = response.Headers.Continuation;

            Assert.IsTrue(resultSetIterator.HasMoreResults);
            this.ContinueNextExecution = false;

            response = await resultSetIterator.ReadNextAsync(this.CancellationToken);

            this.ContinuationToken = response.Headers.Continuation;

            Assert.IsFalse(resultSetIterator.HasMoreResults);
            Assert.IsNull(response.Headers.Continuation);
        }
        public async Task ReadFeedIteratorCore_ReadAll_MixContinuationToken()
        {
            int totalCount = 0;
            int batchSize  = 1000;

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

            ContainerCore itemsCore = this.LargerContainer;

            // Do a read without FeedToken and get the older CT from Header
            string           olderContinuationToken = null;
            FeedIteratorCore feedIterator           = itemsCore.GetItemQueryStreamIterator(queryDefinition: null, requestOptions: new QueryRequestOptions()
            {
                MaxItemCount = 1
            }) as FeedIteratorCore;

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

            // start a new iterator using the older CT and expect it to continue
            feedIterator = itemsCore.GetItemQueryStreamIterator(queryDefinition: null, continuationToken: olderContinuationToken, requestOptions: new QueryRequestOptions()
            {
                MaxItemCount = 1
            }) as FeedIteratorCore;
            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(batchSize, totalCount);
        }
        public async Task ChangeFeedIteratorCore_OfT_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 <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>();

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

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

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

            bool creatorCalled = false;
            Func <ResponseMessage, FeedResponse <dynamic> > creator = (ResponseMessage r) =>
            {
                creatorCalled = true;
                return(Mock.Of <FeedResponse <dynamic> >());
            };

            FeedIteratorCore <dynamic> changeFeedIteratorCoreOfT = new FeedIteratorCore <dynamic>(changeFeedIteratorCore, creator);
            FeedResponse <dynamic>     response = await changeFeedIteratorCoreOfT.ReadNextAsync();

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

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

            Assert.IsTrue(creatorCalled, "Response creator not called");
        }
        public async Task ReadFeedIteratorCore_ReadNextAsync()
        {
            string          continuation    = "TBD";
            ResponseMessage responseMessage = new ResponseMessage(HttpStatusCode.OK);

            responseMessage.Headers.ContinuationToken = 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 <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>();

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

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

            FeedIteratorCore feedTokenIterator = FeedIteratorCore.CreateForPartitionedResource(containerCore, new Uri("http://localhost"), Documents.ResourceType.Document, null, null, feedToken, new QueryRequestOptions());
            ResponseMessage  response          = await feedTokenIterator.ReadNextAsync();

            Assert.AreEqual(feedToken, feedTokenIterator.FeedToken);
            Mock.Get(feedToken)
            .Verify(f => f.UpdateContinuation(It.Is <string>(ct => ct == continuation)), Times.Once);

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

            Mock.Get(feedToken)
            .Verify(f => f.IsDone, Times.Once);
        }
        public async Task ReadFeedIteratorCore_PassingFeedToken_ReadAll()
        {
            int totalCount = 0;
            int batchSize  = 1000;

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

            ContainerCore itemsCore = this.LargerContainer;

            FeedIteratorCore initialFeedIterator = itemsCore.GetItemQueryStreamIterator(queryDefinition: null, requestOptions: new QueryRequestOptions()
            {
                MaxItemCount = 1
            }) as FeedIteratorCore;

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

            // Use the previous iterators FeedToken to continue
            FeedIteratorCore feedIterator = itemsCore.GetItemQueryStreamIterator(queryDefinition: null, feedToken: initialFeedIterator.FeedToken) as FeedIteratorCore;

            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(batchSize, totalCount);
        }
        public async Task ReadFeedIteratorCore_WithNoInitialState_ReadNextAsync()
        {
            string          continuation    = "TBD";
            ResponseMessage responseMessage = new ResponseMessage(HttpStatusCode.OK);

            responseMessage.Headers.ContinuationToken = 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 <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>();

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

            FeedIteratorCore feedTokenIterator = FeedIteratorCore.CreateForPartitionedResource(containerCore, new Uri("http://localhost"), Documents.ResourceType.Document, null, null, null, new QueryRequestOptions());
            ResponseMessage  response          = await feedTokenIterator.ReadNextAsync();

            FeedToken feedTokenOut = feedTokenIterator.FeedToken;

            Assert.IsNotNull(feedTokenOut);

            FeedTokenEPKRange feedTokenEPKRange = feedTokenOut as FeedTokenEPKRange;

            // Assert that a FeedToken for the entire range is used
            Assert.AreEqual(Documents.Routing.PartitionKeyInternal.MinimumInclusiveEffectivePartitionKey, feedTokenEPKRange.CompleteRange.Min);
            Assert.AreEqual(Documents.Routing.PartitionKeyInternal.MaximumExclusiveEffectivePartitionKey, feedTokenEPKRange.CompleteRange.Max);
            Assert.AreEqual(continuation, feedTokenEPKRange.CompositeContinuationTokens.Peek().Token);
            Assert.IsFalse(feedTokenEPKRange.IsDone);
        }
        public async Task ReadFeedIteratorCore_AllowsParallelProcessing()
        {
            int batchSize = 1000;

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

            ContainerCore             itemsCore = this.LargerContainer;
            IReadOnlyList <FeedToken> tokens    = await itemsCore.GetFeedTokensAsync();

            List <Task <int> > tasks = tokens.Select(token => Task.Run(async() =>
            {
                int count = 0;
                FeedIteratorCore feedIterator = itemsCore.GetItemQueryStreamIterator(token) as FeedIteratorCore;
                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;
                            count += response.Count;
                        }
                    }
                }

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

            await Task.WhenAll(tasks);

            int documentsRead = 0;

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

            Assert.AreEqual(batchSize, documentsRead);
        }
        public async Task ReadFeedIteratorCore_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));
            });

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

            Mock.Get(containerCore)
            .Setup(c => c.ClientContext)
            .Returns(cosmosClientContext);
            Mock.Get(containerCore)
            .Setup(c => c.LinkUri)
            .Returns(new Uri($"/dbs/db/colls/colls", UriKind.Relative));
            FeedTokenInternal feedToken = Mock.Of <FeedTokenInternal>();

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

            FeedIteratorCore changeFeedIteratorCore = FeedIteratorCore.CreateForPartitionedResource(containerCore, new Uri($"/dbs/db/colls/colls", UriKind.Relative), Documents.ResourceType.Document, null, null, feedToken, new QueryRequestOptions());

            ResponseMessage response = await changeFeedIteratorCore.ReadNextAsync();

            Assert.AreEqual(1, executionCount, "Pipeline handled the Split");
            Assert.AreEqual(HttpStatusCode.Gone, response.StatusCode);
        }
Esempio n. 9
0
        public async Task ReadFeedIteratorCore_OfT_ReadNextAsync()
        {
            string          continuation    = "TBD";
            ResponseMessage responseMessage = new ResponseMessage(HttpStatusCode.OK);

            responseMessage.Headers.ContinuationToken = continuation;
            responseMessage.Headers[Documents.HttpConstants.HttpHeaders.ItemCount] = "1";
            responseMessage.Content = new MemoryStream(Encoding.UTF8.GetBytes("{}"));

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

            cosmosClientContext.Setup(c => c.ClientOptions).Returns(new CosmosClientOptions());
            cosmosClientContext
            .Setup(c => c.ProcessResourceOperationStreamAsync(
                       It.IsAny <string>(),
                       It.Is <Documents.ResourceType>(rt => rt == Documents.ResourceType.Document),
                       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.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.GetContinuation())
            .Returns(continuation);
            Mock.Get(feedToken)
            .Setup(f => f.IsDone)
            .Returns(true);

            FeedRangeIteratorCore feedTokenIterator = new FeedRangeIteratorCore(containerCore, feedToken, new QueryRequestOptions(), Documents.ResourceType.Document, queryDefinition: null);
            bool creatorCalled = false;
            Func <ResponseMessage, FeedResponse <dynamic> > creator = (ResponseMessage r) =>
            {
                creatorCalled = true;
                return(Mock.Of <FeedResponse <dynamic> >());
            };

            FeedIteratorCore <dynamic> feedTokenIteratorOfT = new FeedIteratorCore <dynamic>(feedTokenIterator, creator);
            FeedResponse <dynamic>     response             = await feedTokenIteratorOfT.ReadNextAsync();

            Assert.IsTrue(creatorCalled, "Response creator not called");
            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);
        }