예제 #1
0
        public async Task ChangeFeedIteratorCore_UpdatesContinuation_On304()
        {
            IDocumentContainer documentContainer = await CreateDocumentContainerAsync(numItems : 0);

            ChangeFeedIteratorCore changeFeedIteratorCore = new ChangeFeedIteratorCore(
                documentContainer,
                ChangeFeedMode.Incremental,
                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);
        }
예제 #2
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);
        }
        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);
        }
        public void ChangeFeedIteratorCore_HasMoreResultsDefault()
        {
            ChangeFeedIteratorCore changeFeedIteratorCore = new ChangeFeedIteratorCore(Mock.Of <ContainerCore>(), null);

            Assert.IsTrue(changeFeedIteratorCore.HasMoreResults);
        }
        public async Task ChangeFeedIteratorCore_Retries()
        {
            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)
            .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(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));
        }
예제 #6
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);
        }
예제 #7
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);
        }
예제 #8
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);
        }
        public async Task ChangeFeedIteratorCore_Retries()
        {
            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 <FeedRangeRequestMessagePopulatorVisitor>()));
            FeedRangeContinuation feedToken = Mock.Of <FeedRangeContinuation>();

            Mock.Get(feedToken)
            .Setup(f => f.FeedRange)
            .Returns(range);

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

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

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

            Mock.Get(feedToken)
            .Verify(f => f.HandleSplitAsync(It.Is <ContainerInternal>(c => c == containerCore), It.IsAny <ResponseMessage>(), It.IsAny <CancellationToken>()), Times.Exactly(2));
            Mock.Get(feedToken)
            .Verify(f => f.HandleChangeFeedNotModified(It.IsAny <ResponseMessage>()), Times.Exactly(3));

            Mock.Get(cosmosClientContext.Object)
            .Verify(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>()), Times.Exactly(3));
        }
        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 <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 <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);

            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.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);

            Assert.IsTrue(creatorCalled, "Response creator not called");
        }
예제 #11
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);
        }
        public void ChangeFeedIteratorCore_HasMoreResultsDefault()
        {
            ChangeFeedIteratorCore changeFeedIteratorCore = ChangeFeedIteratorCore.Create(Mock.Of <ContainerInternal>(), null, null, null);

            Assert.IsTrue(changeFeedIteratorCore.HasMoreResults);
        }
 public void ChangeFeedIteratorCore_Null_Container()
 {
     ChangeFeedIteratorCore.Create(null, null, null, new ChangeFeedRequestOptions());
 }
예제 #14
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)
            {
            }
        }
예제 #15
0
        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);

            ContainerInternal itemsCore    = this.LargerContainer;
            string            continuation = null;
            int count = 0;

            while (true)
            {
                ChangeFeedRequestOptions requestOptions;
                if (continuation == null)
                {
                    requestOptions = new ChangeFeedRequestOptions()
                    {
                        From = ChangeFeedRequestOptions.StartFrom.CreateFromBeginning(),
                    };
                }
                else
                {
                    requestOptions = new ChangeFeedRequestOptions()
                    {
                        From = ChangeFeedRequestOptions.StartFrom.CreateFromContinuation(continuation),
                    };
                }

                ChangeFeedIteratorCore feedIterator = itemsCore.GetChangeFeedStreamIterator(changeFeedRequestOptions: requestOptions) 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.");
                }
            }
        }