public async Task ShouldReturnNotModifiedOnSingleRange() { // Default mock is 1 range MultiRangeMockDocumentClient documentClient = new MultiRangeMockDocumentClient(); using CosmosClient client = MockCosmosUtil.CreateMockCosmosClient(); Mock <CosmosClientContext> mockContext = new Mock <CosmosClientContext>(); mockContext.Setup(x => x.ClientOptions).Returns(MockCosmosUtil.GetDefaultConfiguration()); mockContext.Setup(x => x.DocumentClient).Returns(new MockDocumentClient()); mockContext.Setup(x => x.SerializerCore).Returns(MockCosmosUtil.Serializer); mockContext.Setup(x => x.Client).Returns(client); mockContext.Setup(x => x.CreateLink(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>())).Returns("/dbs/test/colls/test"); ResponseMessage firstResponse = new ResponseMessage(HttpStatusCode.NotModified); firstResponse.Headers.ETag = "FirstContinuation"; mockContext.SetupSequence(x => x.ProcessResourceOperationAsync <ResponseMessage>( 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 <Func <ResponseMessage, ResponseMessage> >(), It.IsAny <CosmosDiagnosticsContext>(), It.IsAny <CancellationToken>())) .Returns(Task.FromResult(firstResponse)); DatabaseInternal databaseCore = new DatabaseInlineCore(mockContext.Object, "mydb"); StandByFeedIteratorCore iterator = new StandByFeedIteratorCore( mockContext.Object, new ContainerInlineCore(mockContext.Object, databaseCore, "myColl"), ChangeFeedStartFrom.Beginning(), new ChangeFeedRequestOptions() { PageSizeHint = 10, }); ResponseMessage firstRequest = await iterator.ReadNextAsync(); Assert.IsTrue(firstRequest.Headers.ContinuationToken.Contains(firstResponse.Headers.ETag), "Response should contain the first continuation"); Assert.AreEqual(HttpStatusCode.NotModified, firstRequest.StatusCode); mockContext.Verify(x => x.ProcessResourceOperationAsync <ResponseMessage>( 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 <Func <ResponseMessage, ResponseMessage> >(), It.IsAny <CosmosDiagnosticsContext>(), It.IsAny <CancellationToken>()), Times.Once); }
public async Task ShouldContinueUntilResponseOk() { // Setting 3 ranges, first one returns a 304, second returns Ok MultiRangeMockDocumentClient documentClient = new MultiRangeMockDocumentClient(); using CosmosClient client = MockCosmosUtil.CreateMockCosmosClient(); Mock <CosmosClientContext> mockContext = new Mock <CosmosClientContext>(); mockContext.Setup(x => x.ClientOptions).Returns(MockCosmosUtil.GetDefaultConfiguration()); mockContext.Setup(x => x.DocumentClient).Returns(documentClient); mockContext.Setup(x => x.SerializerCore).Returns(MockCosmosUtil.Serializer); mockContext.Setup(x => x.Client).Returns(client); mockContext.Setup(x => x.CreateLink(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>())).Returns("/dbs/test/colls/test"); ResponseMessage firstResponse = new ResponseMessage(HttpStatusCode.NotModified); firstResponse.Headers.ETag = "FirstContinuation"; ResponseMessage secondResponse = new ResponseMessage(HttpStatusCode.OK); secondResponse.Headers.ETag = "SecondContinuation"; mockContext.SetupSequence(x => x.ProcessResourceOperationAsync <ResponseMessage>( It.IsAny <string>(), It.IsAny <Documents.ResourceType>(), It.IsAny <Documents.OperationType>(), It.IsAny <RequestOptions>(), It.IsAny <ContainerInternal>(), It.IsAny <Cosmos.FeedRange>(), It.IsAny <Stream>(), It.IsAny <Action <RequestMessage> >(), It.IsAny <Func <ResponseMessage, ResponseMessage> >(), It.IsAny <ITrace>(), It.IsAny <CancellationToken>())) .Returns(Task.FromResult(firstResponse)) .Returns(Task.FromResult(secondResponse)); DatabaseInternal databaseCore = new DatabaseInlineCore(mockContext.Object, "mydb"); StandByFeedIteratorCore iterator = new StandByFeedIteratorCore( mockContext.Object, new ContainerInlineCore(mockContext.Object, databaseCore, "myColl"), null, 10, new StandByFeedIteratorRequestOptions()); ResponseMessage firstRequest = await iterator.ReadNextAsync(); Assert.IsTrue(firstRequest.Headers.ContinuationToken.Contains(firstResponse.Headers.ETag), "Response should contain the first continuation"); Assert.IsTrue(firstRequest.Headers.ContinuationToken.Contains(secondResponse.Headers.ETag), "Response should contain the second continuation"); Assert.AreEqual(HttpStatusCode.OK, firstRequest.StatusCode); mockContext.Verify(x => x.ProcessResourceOperationAsync <ResponseMessage>( It.IsAny <string>(), It.IsAny <Documents.ResourceType>(), It.IsAny <Documents.OperationType>(), It.IsAny <RequestOptions>(), It.IsAny <ContainerInternal>(), It.IsAny <Cosmos.FeedRange>(), It.IsAny <Stream>(), It.IsAny <Action <RequestMessage> >(), It.IsAny <Func <ResponseMessage, ResponseMessage> >(), It.IsAny <ITrace>(), It.IsAny <CancellationToken>()), Times.Exactly(2)); }
public async Task ShouldReturnNotModifiedAfterCyclingOnAllRanges() { // Setting mock to have 3 ranges, this test will get a 304 on all 3 ranges, do 3 backend requests, and return a 304 MultiRangeMockDocumentClient documentClient = new MultiRangeMockDocumentClient(); CosmosClient client = MockCosmosUtil.CreateMockCosmosClient(); Mock <CosmosClientContext> mockContext = new Mock <CosmosClientContext>(); mockContext.Setup(x => x.ClientOptions).Returns(MockCosmosUtil.GetDefaultConfiguration()); mockContext.Setup(x => x.DocumentClient).Returns(documentClient); mockContext.Setup(x => x.CosmosSerializer).Returns(MockCosmosUtil.Serializer); mockContext.Setup(x => x.Client).Returns(client); ResponseMessage firstResponse = new ResponseMessage(HttpStatusCode.NotModified); firstResponse.Headers.ETag = "FirstContinuation"; ResponseMessage secondResponse = new ResponseMessage(HttpStatusCode.NotModified); secondResponse.Headers.ETag = "SecondContinuation"; ResponseMessage thirdResponse = new ResponseMessage(HttpStatusCode.NotModified); thirdResponse.Headers.ETag = "ThirdContinuation"; mockContext.SetupSequence(x => x.ProcessResourceOperationAsync <ResponseMessage>( 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 <Func <ResponseMessage, ResponseMessage> >(), It.IsAny <CancellationToken>())) .Returns(Task.FromResult(firstResponse)) .Returns(Task.FromResult(secondResponse)) .Returns(Task.FromResult(thirdResponse)); ChangeFeedResultSetIteratorCore iterator = new ChangeFeedResultSetIteratorCore( mockContext.Object, (ContainerCore)client.GetContainer("myDb", "myColl"), null, 10, new ChangeFeedRequestOptions()); ResponseMessage firstRequest = await iterator.ReadNextAsync(); Assert.IsTrue(firstRequest.Headers.ContinuationToken.Contains(firstResponse.Headers.ETag), "Response should contain the first continuation"); Assert.IsTrue(firstRequest.Headers.ContinuationToken.Contains(secondResponse.Headers.ETag), "Response should contain the second continuation"); Assert.IsTrue(firstRequest.Headers.ContinuationToken.Contains(thirdResponse.Headers.ETag), "Response should contain the third continuation"); Assert.AreEqual(HttpStatusCode.NotModified, firstRequest.StatusCode); mockContext.Verify(x => x.ProcessResourceOperationAsync <ResponseMessage>( 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 <Func <ResponseMessage, ResponseMessage> >(), It.IsAny <CancellationToken>()), Times.Exactly(3)); }
public async Task ContinuationTokenIsNotUpdatedOnFails() { MultiRangeMockDocumentClient documentClient = new MultiRangeMockDocumentClient(); CosmosClient client = MockCosmosUtil.CreateMockCosmosClient(); Mock <CosmosClientContext> mockContext = new Mock <CosmosClientContext>(); mockContext.Setup(x => x.ClientOptions).Returns(MockCosmosUtil.GetDefaultConfiguration()); mockContext.Setup(x => x.DocumentClient).Returns(documentClient); mockContext.Setup(x => x.SerializerCore).Returns(MockCosmosUtil.Serializer); mockContext.Setup(x => x.Client).Returns(client); mockContext.Setup(x => x.CreateLink(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>())).Returns(new Uri("/dbs/test/colls/test", UriKind.Relative)); ResponseMessage firstResponse = new ResponseMessage(HttpStatusCode.NotModified); firstResponse.Headers.ETag = "FirstContinuation"; ResponseMessage secondResponse = new ResponseMessage(HttpStatusCode.NotFound); secondResponse.Headers.ETag = "ShouldNotContainThis"; secondResponse.ErrorMessage = "something"; mockContext.SetupSequence(x => x.ProcessResourceOperationAsync <ResponseMessage>( 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 <Func <ResponseMessage, ResponseMessage> >(), It.IsAny <CosmosDiagnosticsContext>(), It.IsAny <CancellationToken>())) .Returns(Task.FromResult(firstResponse)) .Returns(Task.FromResult(secondResponse)); DatabaseCore databaseCore = new DatabaseCore(mockContext.Object, "mydb"); StandByFeedIteratorCore iterator = new StandByFeedIteratorCore( mockContext.Object, new ContainerCore(mockContext.Object, databaseCore, "myColl"), null, 10, new ChangeFeedRequestOptions()); ResponseMessage firstRequest = await iterator.ReadNextAsync(); Assert.IsTrue(firstRequest.Headers.ContinuationToken.Contains(firstResponse.Headers.ETag), "Response should contain the first continuation"); Assert.IsTrue(!firstRequest.Headers.ContinuationToken.Contains(secondResponse.Headers.ETag), "Response should not contain the second continuation"); Assert.AreEqual(HttpStatusCode.NotFound, firstRequest.StatusCode); mockContext.Verify(x => x.ProcessResourceOperationAsync <ResponseMessage>( 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 <Func <ResponseMessage, ResponseMessage> >(), It.IsAny <CosmosDiagnosticsContext>(), It.IsAny <CancellationToken>()), Times.Exactly(2)); }
public async Task FeedRangeCompositeContinuation_HandleSplits_ReadFeed() { List <CompositeContinuationToken> compositeContinuationTokens = new List <CompositeContinuationToken>() { FeedRangeContinuationTests.BuildTokenForRange("A", "C", JsonConvert.SerializeObject(new CompositeContinuationToken() { Token = "token1", Range = new Documents.Routing.Range <string>("A", "C", true, false) })), FeedRangeContinuationTests.BuildTokenForRange("C", "F", JsonConvert.SerializeObject(new CompositeContinuationToken() { Token = "token2", Range = new Documents.Routing.Range <string>("C", "F", true, false) })), }; FeedRangeCompositeContinuation feedRangeCompositeContinuation = new FeedRangeCompositeContinuation(Guid.NewGuid().ToString(), Mock.Of <FeedRangeInternal>(), JsonConvert.DeserializeObject <List <CompositeContinuationToken> >(JsonConvert.SerializeObject(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 <ContainerInternal> containerCore = new Mock <ContainerInternal>(); containerCore .Setup(c => c.ClientContext).Returns(cosmosClientContext.Object); Assert.AreEqual(2, feedRangeCompositeContinuation.CompositeContinuationTokens.Count); ResponseMessage split = new ResponseMessage(HttpStatusCode.Gone); split.Headers.SubStatusCode = Documents.SubStatusCodes.PartitionKeyRangeGone; Assert.IsTrue((await feedRangeCompositeContinuation.HandleSplitAsync(containerCore.Object, split, default(CancellationToken))).ShouldRetry); // verify token state // Split should have updated initial and created a new token at the end Assert.AreEqual(3, feedRangeCompositeContinuation.CompositeContinuationTokens.Count); CompositeContinuationToken[] continuationTokens = feedRangeCompositeContinuation.CompositeContinuationTokens.ToArray(); // First token is split Assert.AreEqual(JsonConvert.DeserializeObject <CompositeContinuationToken>(compositeContinuationTokens[0].Token).Range.Min, JsonConvert.DeserializeObject <CompositeContinuationToken>(continuationTokens[0].Token).Range.Min); Assert.AreEqual(JsonConvert.DeserializeObject <CompositeContinuationToken>(compositeContinuationTokens[0].Token).Token, JsonConvert.DeserializeObject <CompositeContinuationToken>(continuationTokens[0].Token).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(JsonConvert.DeserializeObject <CompositeContinuationToken>(compositeContinuationTokens[0].Token).Range.Max, JsonConvert.DeserializeObject <CompositeContinuationToken>(continuationTokens[2].Token).Range.Max); Assert.AreEqual(JsonConvert.DeserializeObject <CompositeContinuationToken>(compositeContinuationTokens[0].Token).Token, JsonConvert.DeserializeObject <CompositeContinuationToken>(continuationTokens[2].Token).Token); Assert.AreEqual(documentClient.AvailablePartitionKeyRanges[1].MinInclusive, continuationTokens[2].Range.Min); Assert.AreEqual(documentClient.AvailablePartitionKeyRanges[1].MaxExclusive, continuationTokens[2].Range.Max); }
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"; responseMessage.Content = new MemoryStream(Encoding.UTF8.GetBytes("{}")); 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); cosmosClientContext .Setup(c => c.ProcessResourceOperationStreamAsync( It.IsAny <string>(), It.Is <Documents.ResourceType>(rt => rt == Documents.ResourceType.Document), 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); Mock.Get(containerCore) .Setup(c => c.GetRIDAsync(It.IsAny <CancellationToken>())) .ReturnsAsync(Guid.NewGuid().ToString()); FeedRangeIteratorCore feedTokenIterator = FeedRangeIteratorCore.Create(containerCore, null, null, new QueryRequestOptions()); ResponseMessage response = await feedTokenIterator.ReadNextAsync(); Assert.IsTrue(FeedRangeContinuation.TryParse(response.ContinuationToken, out FeedRangeContinuation parsedToken)); FeedRangeCompositeContinuation feedRangeCompositeContinuation = parsedToken as FeedRangeCompositeContinuation; FeedRangeEPK feedTokenEPKRange = feedRangeCompositeContinuation.FeedRange as FeedRangeEPK; // Assert that a FeedToken for the entire range is used Assert.AreEqual(Documents.Routing.PartitionKeyInternal.MinimumInclusiveEffectivePartitionKey, feedTokenEPKRange.Range.Min); Assert.AreEqual(Documents.Routing.PartitionKeyInternal.MaximumExclusiveEffectivePartitionKey, feedTokenEPKRange.Range.Max); Assert.AreEqual(continuation, feedRangeCompositeContinuation.CompositeContinuationTokens.Peek().Token); Assert.IsFalse(feedRangeCompositeContinuation.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 async Task ShouldReturnNotModifiedOnSingleRange() { // Default mock is 1 range MultiRangeMockDocumentClient documentClient = new MultiRangeMockDocumentClient(); CosmosClient client = MockCosmosUtil.CreateMockCosmosClient(); Mock <CosmosClientContext> mockContext = new Mock <CosmosClientContext>(); mockContext.Setup(x => x.ClientOptions).Returns(MockCosmosUtil.GetDefaultConfiguration()); mockContext.Setup(x => x.DocumentClient).Returns(new MockDocumentClient()); mockContext.Setup(x => x.CosmosSerializer).Returns(MockCosmosUtil.Serializer); mockContext.Setup(x => x.Client).Returns(client); ResponseMessage firstResponse = new ResponseMessage(HttpStatusCode.NotModified); firstResponse.Headers.ETag = "FirstContinuation"; mockContext.SetupSequence(x => x.ProcessResourceOperationAsync <ResponseMessage>( 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 <Func <ResponseMessage, ResponseMessage> >(), It.IsAny <CancellationToken>())) .Returns(Task.FromResult(firstResponse)); ChangeFeedResultSetIteratorCore iterator = new ChangeFeedResultSetIteratorCore( mockContext.Object, (ContainerCore)client.GetContainer("myDb", "myColl"), null, 10, new ChangeFeedRequestOptions()); ResponseMessage firstRequest = await iterator.ReadNextAsync(); Assert.IsTrue(firstRequest.Headers.ContinuationToken.Contains(firstResponse.Headers.ETag), "Response should contain the first continuation"); Assert.AreEqual(HttpStatusCode.NotModified, firstRequest.StatusCode); mockContext.Verify(x => x.ProcessResourceOperationAsync <ResponseMessage>( 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 <Func <ResponseMessage, ResponseMessage> >(), It.IsAny <CancellationToken>()), Times.Once); }
public async Task GetChangeFeedTokensAsyncReturnsOnePerPartitionKeyRange() { // Setting mock to have 3 ranges, to generate 3 tokens MultiRangeMockDocumentClient documentClient = new MultiRangeMockDocumentClient(); using CosmosClient client = MockCosmosUtil.CreateMockCosmosClient(); Mock <CosmosClientContext> mockContext = new Mock <CosmosClientContext>(); mockContext.Setup(x => x.ClientOptions).Returns(MockCosmosUtil.GetDefaultConfiguration()); mockContext.Setup(x => x.DocumentClient).Returns(documentClient); mockContext.Setup(x => x.SerializerCore).Returns(MockCosmosUtil.Serializer); mockContext.Setup(x => x.Client).Returns(client); mockContext.Setup(x => x.CreateLink(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>())).Returns(UriFactory.CreateDocumentCollectionUri("test", "test").OriginalString); DatabaseInternal db = new DatabaseInlineCore(mockContext.Object, "test"); ContainerInternal container = new ContainerInlineCore(mockContext.Object, db, "test"); IEnumerable <string> tokens = await container.GetChangeFeedTokensAsync(); Assert.AreEqual(3, tokens.Count()); PartitionKeyRangeCache pkRangeCache = await documentClient.GetPartitionKeyRangeCacheAsync(); foreach (string token in tokens) { // Validate that each token represents a StandByFeedContinuationToken with a single Range List <CompositeContinuationToken> deserialized = JsonConvert.DeserializeObject <List <CompositeContinuationToken> >(token); Assert.AreEqual(1, deserialized.Count); CompositeContinuationToken compositeToken = deserialized[0]; IReadOnlyList <Documents.PartitionKeyRange> rangesForTheToken = await pkRangeCache.TryGetOverlappingRangesAsync("", compositeToken.Range); // Token represents one range Assert.AreEqual(1, rangesForTheToken.Count); Assert.AreEqual(rangesForTheToken[0].MinInclusive, compositeToken.Range.Min); Assert.AreEqual(rangesForTheToken[0].MaxExclusive, compositeToken.Range.Max); } }
public async Task ShouldReturnNotModifiedAfterCyclingOnAllRanges() { // Setting mock to have 3 ranges, this test will get a 304 on all 3 ranges, do 3 backend requests, and return a 304 MultiRangeMockDocumentClient documentClient = new MultiRangeMockDocumentClient(); CosmosClient client = MockCosmosUtil.CreateMockCosmosClient(); Mock <CosmosClientContext> mockContext = new Mock <CosmosClientContext>(); mockContext.Setup(x => x.ClientOptions).Returns(MockCosmosUtil.GetDefaultConfiguration()); mockContext.Setup(x => x.DocumentClient).Returns(documentClient); mockContext.Setup(x => x.SerializerCore).Returns(MockCosmosUtil.Serializer); mockContext.Setup(x => x.Client).Returns(client); mockContext.Setup(x => x.CreateLink(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>())).Returns(new Uri("/dbs/test/colls/test", UriKind.Relative)); ResponseMessage firstResponse = new ResponseMessage(HttpStatusCode.NotModified); firstResponse.Headers.ETag = "FirstContinuation"; ResponseMessage secondResponse = new ResponseMessage(HttpStatusCode.NotModified); secondResponse.Headers.ETag = "SecondContinuation"; ResponseMessage thirdResponse = new ResponseMessage(HttpStatusCode.NotModified); thirdResponse.Headers.ETag = "ThirdContinuation"; mockContext.SetupSequence(x => x.ProcessResourceOperationAsync <ResponseMessage>( It.IsAny <Uri>(), 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 <Func <ResponseMessage, ResponseMessage> >(), It.IsAny <CosmosDiagnosticsContext>(), It.IsAny <CancellationToken>())) .Returns(Task.FromResult(firstResponse)) .Returns(Task.FromResult(secondResponse)) .Returns(Task.FromResult(thirdResponse)); DatabaseInternal databaseCore = new DatabaseInlineCore(mockContext.Object, "mydb"); StandByFeedIteratorCore iterator = new StandByFeedIteratorCore( mockContext.Object, new ContainerInlineCore(mockContext.Object, databaseCore, "myColl"), new ChangeFeedRequestOptions() { MaxItemCount = 10, From = ChangeFeedRequestOptions.StartFrom.CreateFromBeginning(), }); ResponseMessage firstRequest = await iterator.ReadNextAsync(); Assert.IsTrue(firstRequest.Headers.ContinuationToken.Contains(firstResponse.Headers.ETag), "Response should contain the first continuation"); Assert.IsTrue(firstRequest.Headers.ContinuationToken.Contains(secondResponse.Headers.ETag), "Response should contain the second continuation"); Assert.IsTrue(firstRequest.Headers.ContinuationToken.Contains(thirdResponse.Headers.ETag), "Response should contain the third continuation"); Assert.AreEqual(HttpStatusCode.NotModified, firstRequest.StatusCode); mockContext.Verify(x => x.ProcessResourceOperationAsync <ResponseMessage>( It.IsAny <Uri>(), 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 <Func <ResponseMessage, ResponseMessage> >(), It.IsAny <CosmosDiagnosticsContext>(), It.IsAny <CancellationToken>()), Times.Exactly(3)); }
public async Task ContinuationTokenIsNotUpdatedOnFails() { MultiRangeMockDocumentClient documentClient = new MultiRangeMockDocumentClient(); using CosmosClient client = MockCosmosUtil.CreateMockCosmosClient(); Mock <CosmosClientContext> mockContext = new Mock <CosmosClientContext>(); mockContext.Setup(x => x.ClientOptions).Returns(MockCosmosUtil.GetDefaultConfiguration()); mockContext.Setup(x => x.DocumentClient).Returns(documentClient); mockContext.Setup(x => x.SerializerCore).Returns(MockCosmosUtil.Serializer); mockContext.Setup(x => x.Client).Returns(client); mockContext.Setup(x => x.CreateLink(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>())).Returns("/dbs/test/colls/test"); ResponseMessage firstResponse = new ResponseMessage(HttpStatusCode.NotModified); firstResponse.Headers.ETag = "FirstContinuation"; ResponseMessage secondResponse = new ResponseMessage( statusCode: HttpStatusCode.NotFound, requestMessage: null, headers: new Headers() { ETag = "ShouldNotContainThis" }, trace: NoOpTrace.Singleton, cosmosException: CosmosExceptionFactory.CreateNotFoundException("something")); mockContext.SetupSequence(x => x.ProcessResourceOperationAsync <ResponseMessage>( It.IsAny <string>(), It.IsAny <Documents.ResourceType>(), It.IsAny <Documents.OperationType>(), It.IsAny <RequestOptions>(), It.IsAny <ContainerInternal>(), It.IsAny <Cosmos.FeedRange>(), It.IsAny <Stream>(), It.IsAny <Action <RequestMessage> >(), It.IsAny <Func <ResponseMessage, ResponseMessage> >(), It.IsAny <ITrace>(), It.IsAny <CancellationToken>())) .Returns(Task.FromResult(firstResponse)) .Returns(Task.FromResult(secondResponse)); DatabaseInternal databaseCore = new DatabaseInlineCore(mockContext.Object, "mydb"); StandByFeedIteratorCore iterator = new StandByFeedIteratorCore( mockContext.Object, new ContainerInlineCore(mockContext.Object, databaseCore, "myColl"), null, 10, new StandByFeedIteratorRequestOptions()); ResponseMessage firstRequest = await iterator.ReadNextAsync(); Assert.IsTrue(firstRequest.Headers.ContinuationToken.Contains(firstResponse.Headers.ETag), "Response should contain the first continuation"); Assert.IsTrue(!firstRequest.Headers.ContinuationToken.Contains(secondResponse.Headers.ETag), "Response should not contain the second continuation"); Assert.AreEqual(HttpStatusCode.NotFound, firstRequest.StatusCode); mockContext.Verify(x => x.ProcessResourceOperationAsync <ResponseMessage>( It.IsAny <string>(), It.IsAny <Documents.ResourceType>(), It.IsAny <Documents.OperationType>(), It.IsAny <RequestOptions>(), It.IsAny <ContainerInternal>(), It.IsAny <Cosmos.FeedRange>(), It.IsAny <Stream>(), It.IsAny <Action <RequestMessage> >(), It.IsAny <Func <ResponseMessage, ResponseMessage> >(), It.IsAny <ITrace>(), It.IsAny <CancellationToken>()), Times.Exactly(2)); }