Example #1
0
        public async Task ChangeFeedIteratorCore_ReadAll()
        {
            int totalCount    = 0;
            int firstRunTotal = 25;
            int batchSize     = 25;

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

            ContainerCore          itemsCore    = this.LargerContainer;
            ChangeFeedIteratorCore feedIterator = itemsCore.GetChangeFeedStreamIterator(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;
                    }

                    continuation = responseMessage.ContinuationToken;
                }
            }

            Assert.AreEqual(firstRunTotal, totalCount);

            int expectedFinalCount = 50;

            // Insert another batch of 25 and use the last FeedToken from the first cycle
            await this.CreateRandomItems(this.LargerContainer, batchSize, randomPartitionKey : true);

            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;
                    }
                }
            }

            Assert.AreEqual(expectedFinalCount, totalCount);
        }
Example #2
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))
                {
                    Assert.IsTrue(FeedRangeCompositeContinuation.TryParse(responseMessage.ContinuationToken, out FeedRangeContinuation continuation));
                    FeedRangeCompositeContinuation    compositeContinuation = continuation as FeedRangeCompositeContinuation;
                    List <CompositeContinuationToken> deserializedToken     = compositeContinuation.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;
                }
            }
        }
Example #3
0
        public async Task ChangeFeedIteratorCore_EmptyBeginning()
        {
            int  totalCount        = 0;
            int  expectedDocuments = 5;
            bool createdDocuments  = false;

            ContainerCore          itemsCore    = this.Container;
            ChangeFeedIteratorCore feedIterator = itemsCore.GetChangeFeedStreamIterator() as ChangeFeedIteratorCore;

            while (feedIterator.HasMoreResults ||
                   (createdDocuments && totalCount == 0))
            {
                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;
                    }
                    else
                    {
                        if (!createdDocuments)
                        {
                            await this.CreateRandomItems(this.Container, expectedDocuments, randomPartitionKey : true);

                            createdDocuments = true;
                        }
                    }
                }
            }

            Assert.AreEqual(expectedDocuments, totalCount);
        }
Example #4
0
        public async Task ChangeFeedIteratorCore_WithMaxItemCount()
        {
            await this.CreateRandomItems(this.Container, 2, randomPartitionKey : true);

            ContainerCore          itemsCore    = this.Container;
            ChangeFeedIteratorCore feedIterator = itemsCore.GetChangeFeedStreamIterator(changeFeedRequestOptions: new ChangeFeedRequestOptions()
            {
                MaxItemCount = 1, StartTime = DateTime.MinValue.ToUniversalTime()
            }) as ChangeFeedIteratorCore;

            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;
                        if (response.Count > 0)
                        {
                            Assert.AreEqual(1, response.Count);
                            return;
                        }
                    }
                }
            }

            Assert.Fail("Found no batch with size 1");
        }
Example #5
0
        public async Task ChangeFeedIteratorCore_StartTime()
        {
            int totalCount = 0;
            int batchSize  = 25;

            await this.CreateRandomItems(this.Container, batchSize, randomPartitionKey : true);

            await Task.Delay(1000);

            DateTime now = DateTime.UtcNow;
            await Task.Delay(1000);

            await this.CreateRandomItems(this.Container, batchSize, randomPartitionKey : true);

            ContainerCore itemsCore    = this.Container;
            FeedIterator  feedIterator = itemsCore.GetChangeFeedStreamIterator(changeFeedRequestOptions: new ChangeFeedRequestOptions()
            {
                StartTime = now
            });

            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;
                    }
                }
            }

            Assert.AreEqual(totalCount, batchSize);
        }
        //[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 ChangeFeedIteratorCore_PartitionKeyRangeId_ReadAll()
        {
            int totalDocuments = 200;

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

            DocumentFeedResponse <Documents.PartitionKeyRange> ranges = await this.LargerContainer.ClientContext.DocumentClient.ReadPartitionKeyRangeFeedAsync(this.LargerContainer.LinkUri);

            List <FeedToken> tokens = new List <FeedToken>(ranges.Count);

            foreach (Documents.PartitionKeyRange range in ranges)
            {
                tokens.Add(new FeedTokenPartitionKeyRange(range.Id));
            }

            ContainerCore      itemsCore = this.LargerContainer;
            List <Task <int> > tasks     = tokens.Select(token => Task.Run(async() =>
            {
                int count = 0;
                ChangeFeedIteratorCore iteratorForToken =
                    itemsCore.GetChangeFeedStreamIterator(token, changeFeedRequestOptions: new ChangeFeedRequestOptions()
                {
                    StartTime = DateTime.MinValue.ToUniversalTime()
                }) as ChangeFeedIteratorCore;
                while (iteratorForToken.HasMoreResults)
                {
                    using (ResponseMessage responseMessage =
                               await iteratorForToken.ReadNextAsync(this.cancellationToken))
                    {
                        if (responseMessage.Content != null)
                        {
                            Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(responseMessage.Content).Data;
                            count += response.Count;
                        }
                    }
                }

                return(count);
            })).ToList();

            await Task.WhenAll(tasks);

            int documentsRead = 0;

            foreach (Task <int> task in tasks)
            {
                documentsRead += task.Result;
            }

            Assert.AreEqual(totalDocuments, documentsRead);
        }
Example #8
0
        public async Task GetFeedRangesAsync_AllowsParallelProcessing()
        {
            int                     pkRangesCount = (await this.LargerContainer.ClientContext.DocumentClient.ReadPartitionKeyRangeFeedAsync(this.LargerContainer.LinkUri)).Count;
            ContainerCore           itemsCore     = this.LargerContainer;
            IEnumerable <FeedRange> tokens        = await itemsCore.GetFeedRangesAsync();

            Assert.IsTrue(pkRangesCount > 1, "Should have created a multi partition container.");
            Assert.AreEqual(pkRangesCount, tokens.Count());
            int totalDocuments = 200;

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

            List <Task <int> > tasks = tokens.Select(token => Task.Run(async() =>
            {
                int count = 0;
                ChangeFeedIteratorCore iteratorForToken =
                    itemsCore.GetChangeFeedStreamIterator(token, changeFeedRequestOptions: new ChangeFeedRequestOptions()
                {
                    StartTime = DateTime.MinValue
                }) as ChangeFeedIteratorCore;
                while (true)
                {
                    using (ResponseMessage responseMessage =
                               await iteratorForToken.ReadNextAsync(this.cancellationToken))
                    {
                        if (!responseMessage.IsSuccessStatusCode)
                        {
                            break;
                        }

                        Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(responseMessage.Content).Data;
                        count += response.Count;
                    }
                }

                return(count);
            })).ToList();

            await Task.WhenAll(tasks);

            int documentsRead = 0;

            foreach (Task <int> task in tasks)
            {
                documentsRead += task.Result;
            }

            Assert.AreEqual(totalDocuments, documentsRead);
        }
        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);
        }
Example #10
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);

            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()
                {
                    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.GetRIDAsync(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 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;

            while (feedIterator.HasMoreResults)
            {
                using (ResponseMessage responseMessage =
                           await feedIterator.ReadNextAsync(this.cancellationToken))
                {
                    Assert.IsNotNull(feedIterator.FeedToken);

                    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(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(feedToken: feedIterator.FeedToken, changeFeedRequestOptions: new ChangeFeedRequestOptions()
            {
                StartTime = DateTime.MinValue.ToUniversalTime()
            }) as ChangeFeedIteratorCore;

            while (setIteratorNew.HasMoreResults)
            {
                using (ResponseMessage responseMessage =
                           await setIteratorNew.ReadNextAsync(this.cancellationToken))
                {
                    Assert.IsNotNull(setIteratorNew.FeedToken);
                    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);
        }