コード例 #1
0
        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;
                }
            }
        }
コード例 #2
0
        public async Task FeedToken_PartitionKeyRange_HandleSplits()
        {
            string containerRid = Guid.NewGuid().ToString();
            string continuation = Guid.NewGuid().ToString();

            FeedTokenPartitionKeyRange feedTokenPartitionKeyRange = new FeedTokenPartitionKeyRange("0");

            feedTokenPartitionKeyRange.UpdateContinuation(continuation);
            PKRangeSplitMockDocumentClient documentClient = new PKRangeSplitMockDocumentClient();

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

            cosmosClientContext.Setup(c => c.ClientOptions).Returns(new CosmosClientOptions());
            cosmosClientContext.Setup(c => c.DocumentClient).Returns(documentClient);

            Mock <ContainerCore> containerCore = new Mock <ContainerCore>();

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

            containerCore
            .Setup(c => c.GetRIDAsync(It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(containerRid));

            ResponseMessage split = new ResponseMessage(HttpStatusCode.Gone);

            split.Headers.SubStatusCode = Documents.SubStatusCodes.PartitionKeyRangeGone;
            Assert.IsTrue(await feedTokenPartitionKeyRange.ShouldRetryAsync(containerCore.Object, split));

            // FeedToken should have converted to EPKRange token

            string            serialization     = feedTokenPartitionKeyRange.ToString();
            FeedTokenEPKRange feedTokenEPKRange = FeedToken.FromString(serialization) as FeedTokenEPKRange;

            Assert.IsNotNull(feedTokenEPKRange, "FeedTokenPartitionKeyRange did not convert to FeedTokenEPKRange after split");
            Assert.AreEqual(containerRid, feedTokenEPKRange.ContainerRid);

            // Split should only capture the sons of the original PKRangeId
            Assert.AreEqual(2, feedTokenEPKRange.CompositeContinuationTokens.Count);
            CompositeContinuationToken[] continuationTokens = feedTokenEPKRange.CompositeContinuationTokens.ToArray();
            // First token is split
            Assert.AreEqual(continuation, continuationTokens[0].Token);
            Assert.AreEqual(documentClient.AvailablePartitionKeyRanges[0].MinInclusive, continuationTokens[0].Range.Min);
            Assert.AreEqual(documentClient.AvailablePartitionKeyRanges[0].MaxExclusive, continuationTokens[0].Range.Max);

            // Second token remains the same
            Assert.AreEqual(continuation, continuationTokens[1].Token);
            Assert.AreEqual(documentClient.AvailablePartitionKeyRanges[1].MinInclusive, continuationTokens[1].Range.Min);
            Assert.AreEqual(documentClient.AvailablePartitionKeyRanges[1].MaxExclusive, continuationTokens[1].Range.Max);
        }
コード例 #3
0
        public void FeedToken_EPK_SingleRange()
        {
            const string containerRid = "containerRid";

            Documents.PartitionKeyRange partitionKeyRange = new Documents.PartitionKeyRange()
            {
                MinInclusive = "A", MaxExclusive = "B"
            };
            FeedTokenEPKRange token = new FeedTokenEPKRange(containerRid, partitionKeyRange);

            Assert.AreEqual(1, token.CompositeContinuationTokens.Count);
            Assert.AreEqual(partitionKeyRange.MinInclusive, token.CompleteRange.Min);
            Assert.AreEqual(partitionKeyRange.MaxExclusive, token.CompleteRange.Max);
        }
コード例 #4
0
        public void IsFeedOperation_ForFeedTokenEPKRange()
        {
            RequestMessage request = new RequestMessage();

            request.OperationType = OperationType.ReadFeed;
            request.ResourceType  = ResourceType.Document;
            FeedTokenInternal feedTokenEPKRange = new FeedTokenEPKRange(Guid.NewGuid().ToString(), new PartitionKeyRange()
            {
                MinInclusive = "AA", MaxExclusive = "BB", Id = "0"
            });

            feedTokenEPKRange.EnrichRequest(request);
            Assert.IsTrue(request.IsPartitionKeyRangeHandlerRequired);
        }
コード例 #5
0
        public void FeedToken_EPK_EnrichRequest()
        {
            const string      containerRid = "containerRid";
            FeedTokenEPKRange token        = new FeedTokenEPKRange(containerRid, new Documents.PartitionKeyRange()
            {
                MinInclusive = "A", MaxExclusive = "B"
            });
            RequestMessage requestMessage = new RequestMessage();

            token.EnrichRequest(requestMessage);
            Assert.AreEqual(token.CompleteRange.Min, requestMessage.Properties[HandlerConstants.StartEpkString]);
            Assert.AreEqual(token.CompleteRange.Max, requestMessage.Properties[HandlerConstants.EndEpkString]);

            Assert.ThrowsException <ArgumentNullException>(() => token.EnrichRequest(null));
        }
コード例 #6
0
        public void FeedToken_EPK_IsDone()
        {
            const string      containerRid = "containerRid";
            FeedTokenEPKRange token        = new FeedTokenEPKRange(containerRid,
                                                                   new Documents.PartitionKeyRange()
            {
                MinInclusive = "A", MaxExclusive = "B"
            });

            token.UpdateContinuation(Guid.NewGuid().ToString());
            Assert.IsFalse(token.IsDone);

            token.UpdateContinuation(null);
            Assert.IsTrue(token.IsDone);
        }
コード例 #7
0
        public async Task FeedToken_EPK_HandleSplits()
        {
            List <CompositeContinuationToken> compositeContinuationTokens = new List <CompositeContinuationToken>()
            {
                FeedTokenTests.BuildTokenForRange("A", "C", "token1"),
                FeedTokenTests.BuildTokenForRange("C", "F", "token2")
            };

            FeedTokenEPKRange feedTokenEPKRange = new FeedTokenEPKRange(Guid.NewGuid().ToString(), new Documents.Routing.Range <string>(compositeContinuationTokens[0].Range.Min, compositeContinuationTokens[1].Range.Min, true, false), compositeContinuationTokens);

            MultiRangeMockDocumentClient documentClient = new MultiRangeMockDocumentClient();

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

            cosmosClientContext.Setup(c => c.ClientOptions).Returns(new CosmosClientOptions());
            cosmosClientContext.Setup(c => c.DocumentClient).Returns(documentClient);

            Mock <ContainerCore> containerCore = new Mock <ContainerCore>();

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

            Assert.AreEqual(2, feedTokenEPKRange.CompositeContinuationTokens.Count);

            ResponseMessage split = new ResponseMessage(HttpStatusCode.Gone);

            split.Headers.SubStatusCode = Documents.SubStatusCodes.PartitionKeyRangeGone;
            Assert.IsTrue(await feedTokenEPKRange.ShouldRetryAsync(containerCore.Object, split));

            // verify token state
            // Split should have updated initial and created a new token at the end
            Assert.AreEqual(3, feedTokenEPKRange.CompositeContinuationTokens.Count);
            CompositeContinuationToken[] continuationTokens = feedTokenEPKRange.CompositeContinuationTokens.ToArray();
            // First token is split
            Assert.AreEqual(compositeContinuationTokens[0].Token, continuationTokens[0].Token);
            Assert.AreEqual(documentClient.AvailablePartitionKeyRanges[0].MinInclusive, continuationTokens[0].Range.Min);
            Assert.AreEqual(documentClient.AvailablePartitionKeyRanges[0].MaxExclusive, continuationTokens[0].Range.Max);

            // Second token remains the same
            Assert.AreEqual(compositeContinuationTokens[1].Token, continuationTokens[1].Token);
            Assert.AreEqual(compositeContinuationTokens[1].Range.Min, continuationTokens[1].Range.Min);
            Assert.AreEqual(compositeContinuationTokens[1].Range.Max, continuationTokens[1].Range.Max);

            // New third token
            Assert.AreEqual(compositeContinuationTokens[0].Token, continuationTokens[2].Token);
            Assert.AreEqual(documentClient.AvailablePartitionKeyRanges[1].MinInclusive, continuationTokens[2].Range.Min);
            Assert.AreEqual(documentClient.AvailablePartitionKeyRanges[1].MaxExclusive, continuationTokens[2].Range.Max);
        }
コード例 #8
0
        public void FeedToken_EPK_NotEnrichRequest_IfEPKAlreadyExists()
        {
            const string      containerRid = "containerRid";
            string            epkString    = Guid.NewGuid().ToString();
            FeedTokenEPKRange token        = new FeedTokenEPKRange(containerRid, new Documents.PartitionKeyRange()
            {
                MinInclusive = "A", MaxExclusive = "B"
            });
            RequestMessage requestMessage = new RequestMessage();

            requestMessage.Properties[HandlerConstants.StartEpkString] = epkString;
            requestMessage.Properties[HandlerConstants.EndEpkString]   = epkString;
            token.EnrichRequest(requestMessage);
            Assert.AreEqual(epkString, requestMessage.Properties[HandlerConstants.StartEpkString]);
            Assert.AreEqual(epkString, requestMessage.Properties[HandlerConstants.EndEpkString]);
        }
コード例 #9
0
        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);
        }
コード例 #10
0
        public void FeedToken_EPK_TryParse()
        {
            const string containerRid = "containerRid";
            List <Documents.PartitionKeyRange> keyRanges = new List <Documents.PartitionKeyRange>()
            {
                new Documents.PartitionKeyRange()
                {
                    MinInclusive = "A", MaxExclusive = "B"
                },
                new Documents.PartitionKeyRange()
                {
                    MinInclusive = "D", MaxExclusive = "E"
                },
            };
            FeedTokenEPKRange token = new FeedTokenEPKRange(containerRid, keyRanges);

            Assert.IsTrue(FeedTokenEPKRange.TryParseInstance(token.ToString(), out FeedToken parsed));
            Assert.IsFalse(FeedTokenEPKRange.TryParseInstance("whatever", out FeedToken _));
        }
コード例 #11
0
        public void FeedToken_EPK_CompleteRange()
        {
            const string containerRid = "containerRid";
            List <Documents.PartitionKeyRange> keyRanges = new List <Documents.PartitionKeyRange>()
            {
                new Documents.PartitionKeyRange()
                {
                    MinInclusive = "A", MaxExclusive = "B"
                },
                new Documents.PartitionKeyRange()
                {
                    MinInclusive = "D", MaxExclusive = "E"
                },
            };
            FeedTokenEPKRange token = new FeedTokenEPKRange(containerRid, keyRanges);

            Assert.AreEqual(keyRanges.Count, token.CompositeContinuationTokens.Count);
            Assert.AreEqual(keyRanges[0].MinInclusive, token.CompleteRange.Min);
            Assert.AreEqual(keyRanges[1].MaxExclusive, token.CompleteRange.Max);
        }
コード例 #12
0
        public void FeedToken_EPK_IsDone_MultipleRanges()
        {
            const string      containerRid = "containerRid";
            FeedTokenEPKRange token        = new FeedTokenEPKRange(containerRid,
                                                                   new List <Documents.PartitionKeyRange>()
            {
                new Documents.PartitionKeyRange()
                {
                    MinInclusive = "A", MaxExclusive = "B"
                },
                new Documents.PartitionKeyRange()
                {
                    MinInclusive = "B", MaxExclusive = "C"
                },
                new Documents.PartitionKeyRange()
                {
                    MinInclusive = "C", MaxExclusive = "D"
                }
            });

            // First range has continuation
            token.UpdateContinuation(Guid.NewGuid().ToString());
            Assert.IsFalse(token.IsDone);

            // Second range is done
            token.UpdateContinuation(null);
            Assert.IsFalse(token.IsDone);

            // Third range is done
            token.UpdateContinuation(null);
            Assert.IsFalse(token.IsDone);

            // First range has continuation
            token.UpdateContinuation(Guid.NewGuid().ToString());
            Assert.IsFalse(token.IsDone);

            // MoveNext should skip the second and third
            // Finish first one
            token.UpdateContinuation(null);
            Assert.IsTrue(token.IsDone);
        }
コード例 #13
0
        public async Task FeedToken_EPK_ShouldRetry()
        {
            List <CompositeContinuationToken> compositeContinuationTokens = new List <CompositeContinuationToken>()
            {
                FeedTokenTests.BuildTokenForRange("A", "C", "token1"),
                FeedTokenTests.BuildTokenForRange("C", "F", "token2")
            };

            FeedTokenEPKRange feedTokenEPKRange = new FeedTokenEPKRange(Guid.NewGuid().ToString(), new Documents.Routing.Range <string>(compositeContinuationTokens[0].Range.Min, compositeContinuationTokens[1].Range.Min, true, false), compositeContinuationTokens);

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

            Assert.IsFalse(await feedTokenEPKRange.ShouldRetryAsync(containerCore, new ResponseMessage(HttpStatusCode.OK)));

            // A 304 on a multi Range token should cycle on all available ranges before stopping retrying
            Assert.IsTrue(await feedTokenEPKRange.ShouldRetryAsync(containerCore, new ResponseMessage(HttpStatusCode.NotModified)));
            feedTokenEPKRange.UpdateContinuation(Guid.NewGuid().ToString());
            Assert.IsTrue(await feedTokenEPKRange.ShouldRetryAsync(containerCore, new ResponseMessage(HttpStatusCode.NotModified)));
            feedTokenEPKRange.UpdateContinuation(Guid.NewGuid().ToString());
            Assert.IsFalse(await feedTokenEPKRange.ShouldRetryAsync(containerCore, new ResponseMessage(HttpStatusCode.NotModified)));
        }
コード例 #14
0
        public async Task FeedToken_EPKRange_Serialization()
        {
            string           continuation   = "TBD";
            List <FeedToken> tokens         = (await this.Container.GetFeedTokensAsync()).ToList();
            List <string>    serializations = new List <string>();

            foreach (FeedToken token in tokens)
            {
                (token as FeedTokenInternal).UpdateContinuation(continuation);
                serializations.Add(token.ToString());
            }

            List <FeedToken> deserialized = new List <FeedToken>();

            foreach (string serialized in serializations)
            {
                FeedToken token = FeedToken.FromString(serialized);
                deserialized.Add(token);
            }

            Assert.AreEqual(tokens.Count, deserialized.Count);

            for (int i = 0; i < tokens.Count; i++)
            {
                FeedTokenEPKRange originalToken     = tokens[i] as FeedTokenEPKRange;
                FeedTokenEPKRange deserializedToken = deserialized[i] as FeedTokenEPKRange;
                Assert.AreEqual(originalToken.GetContinuation(), deserializedToken.GetContinuation());
                Assert.AreEqual(originalToken.ContainerRid, deserializedToken.ContainerRid);
                Assert.AreEqual(originalToken.CompositeContinuationTokens.Count, deserializedToken.CompositeContinuationTokens.Count);
                Assert.AreEqual(originalToken.CompleteRange.Min, deserializedToken.CompleteRange.Min);
                Assert.AreEqual(originalToken.CompleteRange.Max, deserializedToken.CompleteRange.Max);
                Assert.AreEqual(originalToken.CompositeContinuationTokens.Peek().Token, deserializedToken.CompositeContinuationTokens.Peek().Token);
                Assert.AreEqual(originalToken.CompositeContinuationTokens.Peek().Range.Min, deserializedToken.CompositeContinuationTokens.Peek().Range.Min);
                Assert.AreEqual(originalToken.CompositeContinuationTokens.Peek().Range.Max, deserializedToken.CompositeContinuationTokens.Peek().Range.Max);
                Assert.AreEqual(originalToken.CompositeContinuationTokens.Peek().Range.IsMinInclusive, deserializedToken.CompositeContinuationTokens.Peek().Range.IsMinInclusive);
                Assert.AreEqual(originalToken.CompositeContinuationTokens.Peek().Range.IsMaxInclusive, deserializedToken.CompositeContinuationTokens.Peek().Range.IsMaxInclusive);
            }
        }
コード例 #15
0
        public void FeedToken_EPK_Scale()
        {
            const string containerRid = "containerRid";
            List <Documents.PartitionKeyRange> keyRanges = new List <Documents.PartitionKeyRange>()
            {
                new Documents.PartitionKeyRange()
                {
                    MinInclusive = "A", MaxExclusive = "B"
                },
                new Documents.PartitionKeyRange()
                {
                    MinInclusive = "D", MaxExclusive = "E"
                },
            };
            FeedTokenEPKRange         token       = new FeedTokenEPKRange(containerRid, keyRanges);
            IReadOnlyList <FeedToken> splitTokens = token.Scale();

            Assert.AreEqual(keyRanges.Count, splitTokens.Count);

            List <FeedTokenEPKRange> feedTokenEPKRanges = splitTokens.Select(t => t as FeedTokenEPKRange).ToList();

            Assert.AreEqual(keyRanges[0].MinInclusive, feedTokenEPKRanges[0].CompositeContinuationTokens.Peek().Range.Min);
            Assert.AreEqual(keyRanges[0].MaxExclusive, feedTokenEPKRanges[0].CompositeContinuationTokens.Peek().Range.Max);
            Assert.AreEqual(keyRanges[1].MinInclusive, feedTokenEPKRanges[1].CompositeContinuationTokens.Peek().Range.Min);
            Assert.AreEqual(keyRanges[1].MaxExclusive, feedTokenEPKRanges[1].CompositeContinuationTokens.Peek().Range.Max);
            Assert.AreEqual(keyRanges[0].MinInclusive, feedTokenEPKRanges[0].CompleteRange.Min);
            Assert.AreEqual(keyRanges[0].MaxExclusive, feedTokenEPKRanges[0].CompleteRange.Max);
            Assert.AreEqual(keyRanges[1].MinInclusive, feedTokenEPKRanges[1].CompleteRange.Min);
            Assert.AreEqual(keyRanges[1].MaxExclusive, feedTokenEPKRanges[1].CompleteRange.Max);

            FeedTokenEPKRange singleToken = new FeedTokenEPKRange(containerRid, new Documents.PartitionKeyRange()
            {
                MinInclusive = "A", MaxExclusive = "B"
            });

            Assert.AreEqual(0, singleToken.Scale().Count);
        }
コード例 #16
0
        public void FeedToken_EPK_MoveToNextTokenCircles()
        {
            const string containerRid = "containerRid";
            List <Documents.PartitionKeyRange> keyRanges = new List <Documents.PartitionKeyRange>()
            {
                new Documents.PartitionKeyRange()
                {
                    MinInclusive = "A", MaxExclusive = "B"
                },
                new Documents.PartitionKeyRange()
                {
                    MinInclusive = "D", MaxExclusive = "E"
                },
            };
            FeedTokenEPKRange token = new FeedTokenEPKRange(containerRid, keyRanges);

            Assert.AreEqual(keyRanges[0].MinInclusive, token.CompositeContinuationTokens.Peek().Range.Min);
            token.UpdateContinuation("something");
            Assert.AreEqual(keyRanges[1].MinInclusive, token.CompositeContinuationTokens.Peek().Range.Min);
            token.UpdateContinuation("something");
            Assert.AreEqual(keyRanges[0].MinInclusive, token.CompositeContinuationTokens.Peek().Range.Min);
            token.UpdateContinuation("something");
            Assert.AreEqual(keyRanges[1].MinInclusive, token.CompositeContinuationTokens.Peek().Range.Min);
        }