public void FeedRangeCompositeContinuation_TryParse()
        {
            const string containerRid = "containerRid";
            List <Documents.Routing.Range <string> > keyRanges = new List <Documents.Routing.Range <string> >()
            {
                new Documents.Routing.Range <string>("A", "B", true, false),
                new Documents.Routing.Range <string>("D", "E", true, false),
            };
            FeedRangeInternal feedRangeInternal  = new FeedRangeEPK(new Documents.Routing.Range <string>("A", "E", true, false));
            FeedRangeCompositeContinuation token = new FeedRangeCompositeContinuation(containerRid, feedRangeInternal, keyRanges);

            Assert.IsTrue(FeedRangeContinuation.TryParse(token.ToString(), out _));
            Assert.IsFalse(FeedRangeContinuation.TryParse("whatever", out _));
        }
Beispiel #2
0
        private void FeedRange_PartitionKey_Validate(PartitionKey partitionKey)
        {
            string continuationToken = "TBD";
            string containerRid      = Guid.NewGuid().ToString();
            FeedRangePartitionKey          feedTokenPartitionKey       = new FeedRangePartitionKey(partitionKey);
            FeedRangeCompositeContinuation feedRangeSimpleContinuation = new FeedRangeCompositeContinuation(containerRid, feedTokenPartitionKey, new List <Documents.Routing.Range <string> >()
            {
                Documents.Routing.Range <string> .GetEmptyRange("AA")
            }, continuationToken);
            string serialized = feedRangeSimpleContinuation.ToString();

            Assert.IsTrue(FeedRangeContinuation.TryParse(serialized, out FeedRangeContinuation deserialized));
            FeedRangeCompositeContinuation deserializedContinuation = deserialized as FeedRangeCompositeContinuation;
            FeedRangePartitionKey          deserializedFeedRange    = deserializedContinuation.FeedRange as FeedRangePartitionKey;

            Assert.AreEqual(feedTokenPartitionKey.PartitionKey.ToJsonString(), deserializedFeedRange.PartitionKey.ToJsonString());
            Assert.AreEqual(continuationToken, deserializedContinuation.GetContinuation());
        }
Beispiel #3
0
        public async Task FeedRange_EPK_Serialization()
        {
            string           continuation   = "TBD";
            string           containerRid   = Guid.NewGuid().ToString();
            List <FeedRange> ranges         = (await this.Container.GetFeedRangesAsync()).ToList();
            List <string>    serializations = new List <string>();
            List <FeedRangeCompositeContinuation> tokens = new List <FeedRangeCompositeContinuation>();

            foreach (FeedRange range in ranges)
            {
                FeedRangeEpk feedRangeEPK = range as FeedRangeEpk;
                FeedRangeCompositeContinuation feedRangeCompositeContinuation = new FeedRangeCompositeContinuation(containerRid, feedRangeEPK, new List <Documents.Routing.Range <string> >()
                {
                    feedRangeEPK.Range
                }, continuation);
                tokens.Add(feedRangeCompositeContinuation);
                serializations.Add(feedRangeCompositeContinuation.ToString());
            }

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

            foreach (string serialized in serializations)
            {
                Assert.IsTrue(FeedRangeContinuation.TryParse(serialized, out FeedRangeContinuation token));
                deserialized.Add(token);
            }

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

            for (int i = 0; i < tokens.Count; i++)
            {
                FeedRangeCompositeContinuation originalToken     = tokens[i] as FeedRangeCompositeContinuation;
                FeedRangeCompositeContinuation deserializedToken = deserialized[i] as FeedRangeCompositeContinuation;
                Assert.AreEqual(originalToken.GetContinuation(), deserializedToken.GetContinuation());
                Assert.AreEqual(originalToken.ContainerRid, deserializedToken.ContainerRid);
                Assert.AreEqual(originalToken.CompositeContinuationTokens.Count, deserializedToken.CompositeContinuationTokens.Count);
                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);
            }
        }
Beispiel #4
0
        public async Task FeedRange_PKRangeId_Serialization()
        {
            string continuationToken = "TBD";
            string containerRid      = Guid.NewGuid().ToString();
            DocumentFeedResponse <Documents.PartitionKeyRange> ranges = await this.Container.ClientContext.DocumentClient.ReadPartitionKeyRangeFeedAsync(this.Container.LinkUri);

            Documents.PartitionKeyRange oneRange = ranges.First();

            FeedRangePartitionKeyRange     original = new FeedRangePartitionKeyRange(oneRange.Id);
            FeedRangeCompositeContinuation feedRangeSimpleContinuation = new FeedRangeCompositeContinuation(containerRid, original, new List <Documents.Routing.Range <string> >()
            {
                oneRange.ToRange()
            }, continuationToken);
            string serialized = feedRangeSimpleContinuation.ToString();

            Assert.IsTrue(FeedRangeContinuation.TryParse(serialized, out FeedRangeContinuation feedRangeContinuation));
            FeedRangeCompositeContinuation deserialized          = feedRangeContinuation as FeedRangeCompositeContinuation;
            FeedRangePartitionKeyRange     deserializedFeedRange = deserialized.FeedRange as FeedRangePartitionKeyRange;

            Assert.IsNotNull(deserialized, "Error deserializing to FeedRangePartitionKeyRange");
            Assert.AreEqual(original.PartitionKeyRangeId, deserializedFeedRange.PartitionKeyRangeId);
            Assert.AreEqual(continuationToken, deserialized.GetContinuation());
        }
Beispiel #5
0
        public void ReadFeedIteratorCore_Create_WithFeedContinuation()
        {
            string       continuation = Guid.NewGuid().ToString();
            FeedRangeEPK feedRangeEPK = FeedRangeEPK.ForFullRange();
            FeedRangeCompositeContinuation feedRangeSimpleContinuation = new FeedRangeCompositeContinuation(Guid.NewGuid().ToString(), feedRangeEPK, new List <Documents.Routing.Range <string> >()
            {
                feedRangeEPK.Range
            }, continuation);
            FeedRangeIteratorCore feedTokenIterator = FeedRangeIteratorCore.Create(Mock.Of <ContainerInternal>(), null, feedRangeSimpleContinuation.ToString(), null);
            FeedRangeEPK          defaultRange      = feedTokenIterator.FeedRangeInternal as FeedRangeEPK;

            Assert.AreEqual(FeedRangeEPK.ForFullRange().Range.Min, defaultRange.Range.Min);
            Assert.AreEqual(FeedRangeEPK.ForFullRange().Range.Max, defaultRange.Range.Max);
            Assert.IsNotNull(feedTokenIterator.FeedRangeContinuation);
            Assert.AreEqual(continuation, feedTokenIterator.FeedRangeContinuation.GetContinuation());
        }
        public override async Task <ResponseMessage> ReadNextAsync(
            ITrace trace,
            CancellationToken cancellationToken = default)
        {
            if (trace == null)
            {
                throw new ArgumentNullException(nameof(trace));
            }

            cancellationToken.ThrowIfCancellationRequested();

            if (!this.hasMoreResults)
            {
                throw new InvalidOperationException("Should not be calling FeedIterator that does not have any more results");
            }

            if (this.monadicEnumerator.Failed)
            {
                this.hasMoreResults = false;

                CosmosException cosmosException = ExceptionToCosmosException.CreateFromException(this.monadicEnumerator.Exception);
                return(new ResponseMessage(
                           statusCode: System.Net.HttpStatusCode.BadRequest,
                           requestMessage: null,
                           headers: cosmosException.Headers,
                           cosmosException: cosmosException,
                           trace: trace));
            }

            CrossPartitionReadFeedAsyncEnumerator enumerator = this.monadicEnumerator.Result;
            TryCatch <CrossFeedRangePage <Pagination.ReadFeedPage, ReadFeedState> > monadicPage;

            try
            {
                if (!await enumerator.MoveNextAsync(trace))
                {
                    throw new InvalidOperationException("Should not be calling enumerator that does not have any more results");
                }

                monadicPage = enumerator.Current;
            }
            catch (Exception ex)
            {
                monadicPage = TryCatch <CrossFeedRangePage <Pagination.ReadFeedPage, ReadFeedState> > .FromException(ex);
            }

            if (monadicPage.Failed)
            {
                CosmosException cosmosException = ExceptionToCosmosException.CreateFromException(monadicPage.Exception);
                if (!IsRetriableException(cosmosException))
                {
                    this.hasMoreResults = false;
                }

                return(new ResponseMessage(
                           statusCode: cosmosException.StatusCode,
                           requestMessage: null,
                           headers: cosmosException.Headers,
                           cosmosException: cosmosException,
                           trace: trace));
            }

            CrossFeedRangePage <Pagination.ReadFeedPage, ReadFeedState> crossFeedRangePage = monadicPage.Result;

            if (crossFeedRangePage.State == default)
            {
                this.hasMoreResults = false;
            }

            // Make the continuation token match the older format:
            string continuationToken;

            if (crossFeedRangePage.State != null)
            {
                List <CompositeContinuationToken>   compositeContinuationTokens = new List <CompositeContinuationToken>();
                CrossFeedRangeState <ReadFeedState> crossFeedRangeState         = crossFeedRangePage.State;
                for (int i = 0; i < crossFeedRangeState.Value.Length; i++)
                {
                    FeedRangeState <ReadFeedState> feedRangeState = crossFeedRangeState.Value.Span[i];
                    FeedRangeEpk feedRange;
                    if (feedRangeState.FeedRange is FeedRangeEpk feedRangeEpk)
                    {
                        feedRange = feedRangeEpk;
                    }
                    else
                    {
                        feedRange = FeedRangeEpk.FullRange;
                    }

                    ReadFeedState readFeedState = feedRangeState.State;
                    CompositeContinuationToken compositeContinuationToken = new CompositeContinuationToken()
                    {
                        Range = feedRange.Range,
                        Token = readFeedState is ReadFeedBeginningState ? null : ((ReadFeedContinuationState)readFeedState).ContinuationToken.ToString(),
                    };

                    compositeContinuationTokens.Add(compositeContinuationToken);
                }

                FeedRangeInternal outerFeedRange;
                if ((this.queryRequestOptions != null) && this.queryRequestOptions.PartitionKey.HasValue)
                {
                    outerFeedRange = new FeedRangePartitionKey(this.queryRequestOptions.PartitionKey.Value);
                }
                else if ((this.queryRequestOptions != null) && (this.queryRequestOptions.FeedRange != null))
                {
                    outerFeedRange = (FeedRangeInternal)this.queryRequestOptions.FeedRange;
                }
                else
                {
                    outerFeedRange = FeedRangeEpk.FullRange;
                }

                FeedRangeCompositeContinuation feedRangeCompositeContinuation = new FeedRangeCompositeContinuation(
                    containerRid: string.Empty,
                    feedRange: outerFeedRange,
                    compositeContinuationTokens);

                continuationToken = feedRangeCompositeContinuation.ToString();
            }
            else
            {
                continuationToken = null;
            }

            Pagination.ReadFeedPage page = crossFeedRangePage.Page;
            Headers headers = new Headers()
            {
                RequestCharge     = page.RequestCharge,
                ActivityId        = page.ActivityId,
                ContinuationToken = continuationToken,
            };

            foreach (KeyValuePair <string, string> kvp in page.AdditionalHeaders)
            {
                headers[kvp.Key] = kvp.Value;
            }

            return(new ResponseMessage(
                       statusCode: System.Net.HttpStatusCode.OK,
                       requestMessage: default,
Beispiel #7
0
        public override async Task <ResponseMessage> ReadNextAsync(CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

            TryCatch <CrossPartitionChangeFeedAsyncEnumerator> monadicEnumerator = await this.lazyMonadicEnumerator.GetValueAsync(cancellationToken);

            if (monadicEnumerator.Failed)
            {
                Exception       createException = monadicEnumerator.Exception;
                CosmosException cosmosException = ExceptionToCosmosException.CreateFromException(createException);
                return(new ResponseMessage(
                           cosmosException.StatusCode,
                           requestMessage: null,
                           headers: cosmosException.Headers,
                           cosmosException: cosmosException,
                           diagnostics: new CosmosDiagnosticsContextCore()));
            }

            CrossPartitionChangeFeedAsyncEnumerator enumerator = monadicEnumerator.Result;

            if (!await enumerator.MoveNextAsync())
            {
                throw new InvalidOperationException("ChangeFeed enumerator should always have a next continuation");
            }

            if (enumerator.Current.Failed)
            {
                CosmosException cosmosException = ExceptionToCosmosException.CreateFromException(enumerator.Current.Exception);
                if (!IsRetriableException(cosmosException))
                {
                    this.hasMoreResults = false;
                }

                return(new ResponseMessage(
                           cosmosException.StatusCode,
                           requestMessage: null,
                           headers: cosmosException.Headers,
                           cosmosException: cosmosException,
                           diagnostics: new CosmosDiagnosticsContextCore()));
            }

            CrossFeedRangePage <Pagination.ChangeFeedPage, ChangeFeedState> crossFeedRangePage = enumerator.Current.Result;

            Pagination.ChangeFeedPage changeFeedPage = crossFeedRangePage.Page;
            ResponseMessage           responseMessage;

            if (changeFeedPage is Pagination.ChangeFeedSuccessPage changeFeedSuccessPage)
            {
                responseMessage = new ResponseMessage(statusCode: System.Net.HttpStatusCode.OK)
                {
                    Content = changeFeedSuccessPage.Content
                };
            }
            else
            {
                responseMessage = new ResponseMessage(statusCode: System.Net.HttpStatusCode.NotModified);
            }

            CrossFeedRangeState <ChangeFeedState> crossFeedRangeState = crossFeedRangePage.State;
            string continuationToken;

            if (this.changeFeedRequestOptions.EmitOldContinuationToken)
            {
                List <CompositeContinuationToken> compositeContinuationTokens = new List <CompositeContinuationToken>();
                for (int i = 0; i < crossFeedRangeState.Value.Length; i++)
                {
                    FeedRangeState <ChangeFeedState> changeFeedFeedRangeState = crossFeedRangeState.Value.Span[i];
                    string token = changeFeedFeedRangeState.State is ChangeFeedStateContinuation changeFeedStateContinuation ? ((CosmosString)changeFeedStateContinuation.ContinuationToken).Value : null;
                    Documents.Routing.Range <string> range = ((FeedRangeEpk)changeFeedFeedRangeState.FeedRange).Range;
                    CompositeContinuationToken       compositeContinuationToken = new CompositeContinuationToken()
                    {
                        Range = range,
                        Token = token,
                    };

                    compositeContinuationTokens.Add(compositeContinuationToken);
                }

                FeedRangeCompositeContinuation feedRangeCompositeContinuationToken = new FeedRangeCompositeContinuation(
                    await this.documentContainer.GetResourceIdentifierAsync(cancellationToken),
                    FeedRangeEpk.FullRange,
                    compositeContinuationTokens);

                continuationToken = feedRangeCompositeContinuationToken.ToString();
            }
            else
            {
                ChangeFeedCrossFeedRangeState changeFeedCrossFeedRangeState = new ChangeFeedCrossFeedRangeState(crossFeedRangeState.Value);
                continuationToken = VersionedAndRidCheckedCompositeToken.ToCosmosElement(
                    new VersionedAndRidCheckedCompositeToken(
                        VersionedAndRidCheckedCompositeToken.Version.V2,
                        changeFeedCrossFeedRangeState.ToCosmosElement(),
                        await this.documentContainer.GetResourceIdentifierAsync(cancellationToken))).ToString();
            }

            responseMessage.Headers.ContinuationToken = continuationToken;
            responseMessage.Headers.RequestCharge     = changeFeedPage.RequestCharge;
            responseMessage.Headers.ActivityId        = changeFeedPage.ActivityId;

            return(responseMessage);
        }