public async Task FeedToken_PKRangeId_Serialization()
        {
            string continuationToken = "TBD";
            DocumentFeedResponse <Documents.PartitionKeyRange> ranges = await this.Container.ClientContext.DocumentClient.ReadPartitionKeyRangeFeedAsync(this.Container.LinkUri);

            Documents.PartitionKeyRange oneRange = ranges.First();

            FeedTokenPartitionKeyRange original = new FeedTokenPartitionKeyRange(oneRange.Id);

            original.UpdateContinuation(continuationToken);
            string    serialized   = original.ToString();
            FeedToken deserialized = FeedToken.FromString(serialized);
            FeedTokenPartitionKeyRange deserializedFeedToken = deserialized as FeedTokenPartitionKeyRange;

            Assert.IsNotNull(deserialized, "Error deserializing to FeedTokenPartitionKeyRange");
            Assert.AreEqual(original.PartitionKeyRangeId, deserializedFeedToken.PartitionKeyRangeId);
            Assert.AreEqual(continuationToken, deserializedFeedToken.GetContinuation());

            // Verify that the backward compatible way works too
            FeedToken deserializedFromBackwardcompatible = FeedToken.FromString(oneRange.Id);
            FeedTokenPartitionKeyRange deserializedFromBackwardcompatibleToken = deserializedFromBackwardcompatible as FeedTokenPartitionKeyRange;

            Assert.IsNotNull(deserializedFromBackwardcompatibleToken, "Error deserializing to FeedTokenPartitionKeyRange");
            Assert.AreEqual(deserializedFromBackwardcompatibleToken.PartitionKeyRangeId, deserializedFeedToken.PartitionKeyRangeId);
        }
        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);
        }
        private void FeedToken_PartitionKey_Validate(PartitionKey partitionKey)
        {
            string continuationToken = "TBD";
            FeedTokenPartitionKey feedTokenPartitionKey = new FeedTokenPartitionKey(partitionKey);

            feedTokenPartitionKey.UpdateContinuation(continuationToken);
            string                serialized            = feedTokenPartitionKey.ToString();
            FeedToken             deserialized          = FeedToken.FromString(serialized);
            FeedTokenPartitionKey deserializedFeedToken = deserialized as FeedTokenPartitionKey;

            Assert.IsNotNull(deserialized, "Error deserializing to FeedTokenPartitionKey");
            Assert.AreEqual(feedTokenPartitionKey.PartitionKey.ToJsonString(), deserializedFeedToken.PartitionKey.ToJsonString());
            Assert.AreEqual(continuationToken, deserializedFeedToken.GetContinuation());
        }
        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);
        }
        //[Timeout(30000)]
        public async Task ChangeFeedIteratorCore_NoFetchNext()
        {
            int pkRangesCount = (await this.LargerContainer.ClientContext.DocumentClient.ReadPartitionKeyRangeFeedAsync(this.LargerContainer.LinkUri)).Count;

            int expected   = 25;
            int iterations = 0;

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

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

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

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

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

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

                if (iterations++ > pkRangesCount)
                {
                    Assert.Fail("Feed does not contain all elements even after looping through PK ranges. Either the continuation is not moving forward or there is some state problem.");
                }
            }
        }
        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);
            }
        }