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 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); }
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); }
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); }
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)); }
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); }
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); }
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]); }
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 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 _)); }
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); }
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); }
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))); }
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); } }
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); }
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); }