public async Task ChangeFeedIteratorCore_UpdatesContinuation_On304() { IDocumentContainer documentContainer = await CreateDocumentContainerAsync(numItems : 0); ChangeFeedIteratorCore changeFeedIteratorCore = new ChangeFeedIteratorCore( documentContainer, ChangeFeedMode.Incremental, new ChangeFeedRequestOptions(), ChangeFeedStartFrom.Beginning()); ResponseMessage responseMessage = await changeFeedIteratorCore.ReadNextAsync(); Assert.AreEqual(HttpStatusCode.NotModified, responseMessage.StatusCode); string continuationToken = responseMessage.Headers.ContinuationToken; ResponseMessage responseMessage2 = await changeFeedIteratorCore.ReadNextAsync(); Assert.AreEqual(HttpStatusCode.NotModified, responseMessage.StatusCode); string continuationToken2 = responseMessage2.Headers.ContinuationToken; Assert.AreNotEqual(continuationToken, continuationToken2); }
public async Task ChangeFeedIteratorCore_PartitionKey_ReadAll() { int totalCount = 0; int firstRunTotal = 25; int batchSize = 25; string pkToRead = "pkToRead"; string otherPK = "otherPK"; ContainerInternal itemsCore = await this.InitializeContainerAsync(); for (int i = 0; i < batchSize; i++) { await itemsCore.CreateItemAsync(ToDoActivity.CreateRandomToDoActivity(pk: pkToRead)); } for (int i = 0; i < batchSize; i++) { await itemsCore.CreateItemAsync(ToDoActivity.CreateRandomToDoActivity(pk: otherPK)); } ChangeFeedIteratorCore feedIterator = itemsCore.GetChangeFeedStreamIterator( ChangeFeedStartFrom.Beginning( FeedRange.FromPartitionKey( new PartitionKey(pkToRead))), ChangeFeedMode.Incremental, new ChangeFeedRequestOptions() { PageSizeHint = 1, }) as ChangeFeedIteratorCore; string continuation = null; while (feedIterator.HasMoreResults) { using (ResponseMessage responseMessage = await feedIterator.ReadNextAsync(this.cancellationToken)) { if (!responseMessage.IsSuccessStatusCode) { continuation = responseMessage.ContinuationToken; break; } Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(responseMessage.Content).Data; totalCount += response.Count; foreach (ToDoActivity toDoActivity in response) { Assert.AreEqual(pkToRead, toDoActivity.pk); } } } 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 itemsCore.CreateItemAsync(ToDoActivity.CreateRandomToDoActivity(pk: pkToRead)); } ChangeFeedIteratorCore setIteratorNew = itemsCore.GetChangeFeedStreamIterator( ChangeFeedStartFrom.ContinuationToken(continuation), ChangeFeedMode.Incremental) as ChangeFeedIteratorCore; while (setIteratorNew.HasMoreResults) { using (ResponseMessage responseMessage = await setIteratorNew.ReadNextAsync(this.cancellationToken)) { if (!responseMessage.IsSuccessStatusCode) { break; } Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(responseMessage.Content).Data; totalCount += response.Count; foreach (ToDoActivity toDoActivity in response) { Assert.AreEqual(pkToRead, toDoActivity.pk); } } } Assert.AreEqual(expectedFinalCount, totalCount); }
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); }
public void ChangeFeedIteratorCore_HasMoreResultsDefault() { ChangeFeedIteratorCore changeFeedIteratorCore = new ChangeFeedIteratorCore(Mock.Of <ContainerCore>(), null); Assert.IsTrue(changeFeedIteratorCore.HasMoreResults); }
public async Task ChangeFeedIteratorCore_Retries() { string continuation = "TBD"; ResponseMessage responseMessage = new ResponseMessage(HttpStatusCode.OK); responseMessage.Headers.ETag = 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); FeedTokenInternal feedToken = Mock.Of <FeedTokenInternal>(); Mock.Get(feedToken) .Setup(f => f.EnrichRequest(It.IsAny <RequestMessage>())); Mock.Get(feedToken) .SetupSequence(f => f.ShouldRetryAsync(It.Is <ContainerCore>(c => c == containerCore), It.IsAny <ResponseMessage>(), It.IsAny <CancellationToken>())) .Returns(Task.FromResult(true)) .Returns(Task.FromResult(false)); ChangeFeedIteratorCore changeFeedIteratorCore = new ChangeFeedIteratorCore(containerCore, feedToken, null); ResponseMessage response = await changeFeedIteratorCore.ReadNextAsync(); Mock.Get(feedToken) .Verify(f => f.UpdateContinuation(It.IsAny <string>()), Times.Exactly(2)); Mock.Get(feedToken) .Verify(f => f.ShouldRetryAsync(It.Is <ContainerCore>(c => c == containerCore), It.IsAny <ResponseMessage>(), It.IsAny <CancellationToken>()), Times.Exactly(2)); Mock.Get(cosmosClientContext.Object) .Verify(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>()), Times.Exactly(2)); }
public async Task ChangeFeedIteratorCore_FromV2SDK() { int expected = 100; int count = 0; await this.CreateRandomItems(this.LargerContainer, expected, randomPartitionKey : true); IReadOnlyList <FeedRange> feedRanges = await this.LargerContainer.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) { ChangeFeedRequestOptions requestOptions = new ChangeFeedRequestOptions() { StartTime = DateTime.MinValue.ToUniversalTime(), MaxItemCount = 1 }; ChangeFeedIteratorCore feedIterator = this.LargerContainer.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, FeedRange.ToString() = [min,max) string range = feedRange.ToString(); int separator = range.IndexOf(','); string min = range.Substring(1, separator - 1); string max = range.Substring(separator + 1, range.IndexOf(')') - separator - 1); dynamic ctRange = new { min = min, max = max }; List <dynamic> ct = new List <dynamic>() { new { min = min, max = max, token = firstResponse.Headers.ETag, range = ctRange } }; // Extract Etag and manually construct the continuation dynamic oldContinuation = new { V = 0, Range = ctRange, 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 = this.LargerContainer.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); }
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; 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; foreach (ToDoActivity toDoActivity in response) { Assert.AreEqual(pkToRead, toDoActivity.status); } } continuation = responseMessage.ContinuationToken; } } 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(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; foreach (ToDoActivity toDoActivity in response) { Assert.AreEqual(pkToRead, toDoActivity.status); } } } } Assert.AreEqual(expectedFinalCount, totalCount); }
public async Task ChangeFeed_FeedRange_FromV0Token() { ContainerResponse largerContainer = await this.database.CreateContainerAsync( new ContainerProperties(id : Guid.NewGuid().ToString(), partitionKeyPath : "/pk"), throughput : 20000, cancellationToken : this.cancellationToken); ContainerInternal container = (ContainerInlineCore)largerContainer; int expected = 100; int count = 0; await this.CreateRandomItems((ContainerCore)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), changeFeedMode: ChangeFeedMode.Incremental, changeFeedRequestOptions: requestOptions) as ChangeFeedIteratorCore; ResponseMessage firstResponse = await feedIterator.ReadNextAsync(); // Construct the continuation's range, using PKRangeId + ETag List <dynamic> ct = new List <dynamic>() { new { FeedRange = new { type = "Physical Partition Key Range Id", value = pkRangeIds.First() }, State = new { type = "continuation", value = JObject.Parse(firstResponse.ContinuationToken)["Continuation"][0]["State"]["value"].ToString() } } }; if (firstResponse.Content != null) { Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(firstResponse.Content).Data; count += response.Count; } // Extract Etag and manually construct the continuation dynamic oldContinuation = new { V = 2, Rid = await container.GetCachedRIDAsync(cancellationToken : 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, }; ChangeFeedIteratorCore feedIterator = container.GetChangeFeedStreamIterator( changeFeedStartFrom: ChangeFeedStartFrom.ContinuationToken(continuation), changeFeedMode: ChangeFeedMode.Incremental, 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; TryCatch <CosmosElement> monadicParsedToken = CosmosElement.Monadic.Parse(migratedContinuation); Assert.IsFalse(monadicParsedToken.Failed); TryCatch <VersionedAndRidCheckedCompositeToken> monadicVersionedToken = VersionedAndRidCheckedCompositeToken .MonadicCreateFromCosmosElement(monadicParsedToken.Result); Assert.IsFalse(monadicVersionedToken.Failed); VersionedAndRidCheckedCompositeToken versionedAndRidCheckedCompositeToken = monadicVersionedToken.Result; Assert.AreEqual(VersionedAndRidCheckedCompositeToken.Version.V2, versionedAndRidCheckedCompositeToken.VersionNumber); } } Assert.AreEqual(expected, count); }
public async Task ChangeFeedIteratorCore_Retries() { string continuation = "TBD"; ResponseMessage responseMessage = new ResponseMessage(HttpStatusCode.OK); responseMessage.Headers.ETag = 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 <string>(), It.IsAny <Documents.ResourceType>(), It.IsAny <Documents.OperationType>(), It.IsAny <RequestOptions>(), It.IsAny <ContainerInternal>(), It.IsAny <PartitionKey?>(), It.IsAny <Stream>(), It.IsAny <Action <RequestMessage> >(), It.IsAny <CosmosDiagnosticsContext>(), It.IsAny <CancellationToken>())) .Returns(Task.FromResult(responseMessage)); ContainerInternal containerCore = Mock.Of <ContainerInternal>(); Mock.Get(containerCore) .Setup(c => c.ClientContext) .Returns(cosmosClientContext.Object); FeedRangeInternal range = Mock.Of <FeedRangeInternal>(); Mock.Get(range) .Setup(f => f.Accept(It.IsAny <FeedRangeRequestMessagePopulatorVisitor>())); FeedRangeContinuation feedToken = Mock.Of <FeedRangeContinuation>(); Mock.Get(feedToken) .Setup(f => f.FeedRange) .Returns(range); Mock.Get(feedToken) .SetupSequence(f => f.HandleSplitAsync(It.Is <ContainerInternal>(c => c == containerCore), It.IsAny <ResponseMessage>(), It.IsAny <CancellationToken>())) .Returns(Task.FromResult(Documents.ShouldRetryResult.RetryAfter(TimeSpan.Zero))) .Returns(Task.FromResult(Documents.ShouldRetryResult.NoRetry())); Mock.Get(feedToken) .SetupSequence(f => f.HandleChangeFeedNotModified(It.IsAny <ResponseMessage>())) .Returns(Documents.ShouldRetryResult.RetryAfter(TimeSpan.Zero)) .Returns(Documents.ShouldRetryResult.NoRetry()) .Returns(Documents.ShouldRetryResult.NoRetry()); ChangeFeedIteratorCore changeFeedIteratorCore = CreateWithCustomFeedToken(containerCore, feedToken); ResponseMessage response = await changeFeedIteratorCore.ReadNextAsync(); Mock.Get(feedToken) .Verify(f => f.ReplaceContinuation(It.IsAny <string>()), Times.Once); Mock.Get(feedToken) .Verify(f => f.HandleSplitAsync(It.Is <ContainerInternal>(c => c == containerCore), It.IsAny <ResponseMessage>(), It.IsAny <CancellationToken>()), Times.Exactly(2)); Mock.Get(feedToken) .Verify(f => f.HandleChangeFeedNotModified(It.IsAny <ResponseMessage>()), Times.Exactly(3)); Mock.Get(cosmosClientContext.Object) .Verify(c => c.ProcessResourceOperationStreamAsync( It.IsAny <string>(), It.IsAny <Documents.ResourceType>(), It.IsAny <Documents.OperationType>(), It.IsAny <RequestOptions>(), It.IsAny <ContainerInternal>(), It.IsAny <PartitionKey?>(), It.IsAny <Stream>(), It.IsAny <Action <RequestMessage> >(), It.IsAny <CosmosDiagnosticsContext>(), It.IsAny <CancellationToken>()), Times.Exactly(3)); }
public async Task ChangeFeedIteratorCore_OfT_ReadNextAsync() { string continuation = "TBD"; ResponseMessage responseMessage = new ResponseMessage(HttpStatusCode.OK); responseMessage.Headers.ETag = 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 <string>(), It.IsAny <Documents.ResourceType>(), It.IsAny <Documents.OperationType>(), It.IsAny <RequestOptions>(), It.IsAny <ContainerInternal>(), It.IsAny <PartitionKey?>(), It.IsAny <Stream>(), It.IsAny <Action <RequestMessage> >(), It.IsAny <CosmosDiagnosticsContext>(), It.IsAny <CancellationToken>())) .Returns(Task.FromResult(responseMessage)); ContainerInternal containerCore = Mock.Of <ContainerInternal>(); Mock.Get(containerCore) .Setup(c => c.ClientContext) .Returns(cosmosClientContext.Object); FeedRangeInternal range = Mock.Of <FeedRangeInternal>(); Mock.Get(range) .Setup(f => f.Accept(It.IsAny <FeedRangeRequestMessagePopulatorVisitor>())); FeedRangeContinuation feedToken = Mock.Of <FeedRangeContinuation>(); Mock.Get(feedToken) .Setup(f => f.FeedRange) .Returns(range); Mock.Get(feedToken) .Setup(f => f.HandleSplitAsync(It.Is <ContainerInternal>(c => c == containerCore), It.IsAny <ResponseMessage>(), It.IsAny <CancellationToken>())) .Returns(Task.FromResult(Documents.ShouldRetryResult.NoRetry())); Mock.Get(feedToken) .Setup(f => f.HandleChangeFeedNotModified(It.IsAny <ResponseMessage>())) .Returns(Documents.ShouldRetryResult.NoRetry()); ChangeFeedIteratorCore changeFeedIteratorCore = CreateWithCustomFeedToken(containerCore, feedToken); bool creatorCalled = false; Func <ResponseMessage, FeedResponse <dynamic> > creator = (ResponseMessage r) => { creatorCalled = true; return(Mock.Of <FeedResponse <dynamic> >()); }; FeedIteratorCore <dynamic> changeFeedIteratorCoreOfT = new FeedIteratorCore <dynamic>(changeFeedIteratorCore, creator); FeedResponse <dynamic> response = await changeFeedIteratorCoreOfT.ReadNextAsync(); Mock.Get(feedToken) .Verify(f => f.ReplaceContinuation(It.Is <string>(ct => ct == continuation)), Times.Once); Mock.Get(feedToken) .Verify(f => f.HandleSplitAsync(It.Is <ContainerInternal>(c => c == containerCore), It.IsAny <ResponseMessage>(), It.IsAny <CancellationToken>()), Times.Once); Mock.Get(feedToken) .Verify(f => f.HandleChangeFeedNotModified(It.IsAny <ResponseMessage>()), Times.Once); Assert.IsTrue(creatorCalled, "Response creator not called"); }
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); ContainerInternal container = (ContainerInlineCore)largerContainer; int expected = 100; int count = 0; await this.CreateRandomItems((ContainerCore)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.GetCachedRIDAsync(cancellationToken : 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 void ChangeFeedIteratorCore_HasMoreResultsDefault() { ChangeFeedIteratorCore changeFeedIteratorCore = ChangeFeedIteratorCore.Create(Mock.Of <ContainerInternal>(), null, null, null); Assert.IsTrue(changeFeedIteratorCore.HasMoreResults); }
public void ChangeFeedIteratorCore_Null_Container() { ChangeFeedIteratorCore.Create(null, null, null, new ChangeFeedRequestOptions()); }
public async Task TestCancellationTokenAsync() { CancellationTokenRequestHandler cancellationTokenHandler = new CancellationTokenRequestHandler(); ContainerInternal itemsCore = await this.InitializeContainerAsync(); await this.CreateRandomItems(itemsCore, 100, randomPartitionKey : true); // Inject validating handler RequestHandler currentInnerHandler = this.cosmosClient.RequestHandler.InnerHandler; this.cosmosClient.RequestHandler.InnerHandler = cancellationTokenHandler; cancellationTokenHandler.InnerHandler = currentInnerHandler; { // Test to see if the token flows to the pipeline CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); ChangeFeedIteratorCore feedIterator = itemsCore.GetChangeFeedStreamIterator( ChangeFeedStartFrom.Beginning(), ChangeFeedMode.Incremental) as ChangeFeedIteratorCore; await feedIterator.ReadNextAsync(cancellationTokenSource.Token); Assert.AreEqual(cancellationTokenSource.Token, cancellationTokenHandler.LastUsedToken, "The token passed did not reach the pipeline"); } // See if cancellation token is honored for first request try { CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); cancellationTokenSource.Cancel(); ChangeFeedIteratorCore feedIterator = itemsCore.GetChangeFeedStreamIterator( ChangeFeedStartFrom.Beginning(), ChangeFeedMode.Incremental) as ChangeFeedIteratorCore; await feedIterator.ReadNextAsync(cancellationTokenSource.Token); Assert.Fail("Expected exception."); } catch (OperationCanceledException) { } // See if cancellation token is honored for second request try { CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); cancellationTokenSource.Cancel(); ChangeFeedIteratorCore feedIterator = itemsCore.GetChangeFeedStreamIterator( ChangeFeedStartFrom.Beginning(), ChangeFeedMode.Incremental) as ChangeFeedIteratorCore; await feedIterator.ReadNextAsync(); await feedIterator.ReadNextAsync(cancellationTokenSource.Token); Assert.Fail("Expected exception."); } catch (OperationCanceledException) { } // See if cancellation token is honored mid draining try { CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); ChangeFeedIteratorCore feedIterator = itemsCore.GetChangeFeedStreamIterator( ChangeFeedStartFrom.Beginning(), ChangeFeedMode.Incremental) as ChangeFeedIteratorCore; await feedIterator.ReadNextAsync(cancellationTokenSource.Token); cancellationTokenSource.Cancel(); await feedIterator.ReadNextAsync(cancellationTokenSource.Token); Assert.Fail("Expected exception."); } catch (OperationCanceledException) { } }
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); ContainerInternal itemsCore = this.LargerContainer; string continuation = null; int count = 0; while (true) { ChangeFeedRequestOptions requestOptions; if (continuation == null) { requestOptions = new ChangeFeedRequestOptions() { From = ChangeFeedRequestOptions.StartFrom.CreateFromBeginning(), }; } else { requestOptions = new ChangeFeedRequestOptions() { From = ChangeFeedRequestOptions.StartFrom.CreateFromContinuation(continuation), }; } ChangeFeedIteratorCore feedIterator = itemsCore.GetChangeFeedStreamIterator(changeFeedRequestOptions: requestOptions) as ChangeFeedIteratorCore; using (ResponseMessage responseMessage = await feedIterator.ReadNextAsync(this.cancellationToken)) { if (responseMessage.IsSuccessStatusCode) { Collection <ToDoActivity> response = TestCommon.SerializerCore.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(responseMessage.Content).Data; count += response.Count; } else { if (responseMessage.StatusCode != HttpStatusCode.NotModified) { Assert.Fail(responseMessage.ErrorMessage); } } continuation = responseMessage.ContinuationToken; } 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."); } } }