public async Task TestCosmosOrderByQueryExecutionContextWithFailurePageAsync(bool createInitialContinuationToken) { int maxPageSize = 5; List <MockPartitionResponse[]> mockResponsesScenario = MockQueryFactory.GetFailureScenarios(); Mock <CosmosQueryClient> mockQueryClient = new Mock <CosmosQueryClient>(); foreach (MockPartitionResponse[] mockResponse in mockResponsesScenario) { string initialContinuationToken = null; string fullContinuationToken = null; if (createInitialContinuationToken) { ToDoItem itemToRepresentPreviousQuery = ToDoItem.CreateItems( 1, "itemToRepresentPreviousQuery", MockQueryFactory.DefaultCollectionRid).First(); initialContinuationToken = $" - RID:{itemToRepresentPreviousQuery._rid} ==#RT:1#TRC:1"; CompositeContinuationToken compositeContinuation = new CompositeContinuationToken() { Range = new Documents.Routing.Range <string>( min: MockQueryFactory.DefaultPartitionKeyRange.MinInclusive, max: MockQueryFactory.DefaultPartitionKeyRange.MaxExclusive, isMaxInclusive: false, isMinInclusive: true), Token = initialContinuationToken }; List <OrderByItem> orderByItems = new List <OrderByItem>() { new OrderByItem(CosmosObject.CreateFromBuffer(Encoding.UTF8.GetBytes("{\"item\":\"2c4ce711-13c3-4c93-817c-49287b71b6c3\"}"))) }; OrderByContinuationToken orderByContinuationToken = new OrderByContinuationToken( compositeContinuationToken: compositeContinuation, orderByItems: orderByItems, rid: itemToRepresentPreviousQuery._rid, skipCount: 0, filter: null); fullContinuationToken = CosmosArray.Create( new List <CosmosElement>() { OrderByContinuationToken.ToCosmosElement(orderByContinuationToken) }).ToString(); } IList <ToDoItem> allItems = MockQueryFactory.GenerateAndMockResponse( mockQueryClient, isOrderByQuery: true, sqlQuerySpec: MockQueryFactory.DefaultQuerySpec, containerRid: MockQueryFactory.DefaultCollectionRid, initContinuationToken: initialContinuationToken, maxPageSize: maxPageSize, mockResponseForSinglePartition: mockResponse, cancellationTokenForMocks: this.cancellationToken); // Order by drains the partitions until it finds an item // If there are no items then it's not possible to have a continuation token if (allItems.Count == 0 && createInitialContinuationToken) { continue; } CosmosQueryContext context = MockQueryFactory.CreateContext( mockQueryClient.Object); QueryInfo queryInfo = new QueryInfo() { OrderBy = new SortOrder[] { SortOrder.Ascending }, OrderByExpressions = new string[] { "id" } }; CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams initParams = new CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams( sqlQuerySpec: MockQueryFactory.DefaultQuerySpec, collectionRid: MockQueryFactory.DefaultCollectionRid, partitionedQueryExecutionInfo: new PartitionedQueryExecutionInfo() { QueryInfo = queryInfo }, partitionKeyRanges: new List <PartitionKeyRange>() { MockQueryFactory.DefaultPartitionKeyRange }, initialPageSize: maxPageSize, maxConcurrency: null, maxItemCount: maxPageSize, maxBufferedItemCount: null, returnResultsInDeterministicOrder: true, testSettings: new TestInjections(simulate429s: false, simulateEmptyPages: false)); TryCatch <IDocumentQueryExecutionComponent> tryCreate = await CosmosOrderByItemQueryExecutionContext.TryCreateAsync( context, initParams, fullContinuationToken != null?CosmosElement.Parse(fullContinuationToken) : null, this.cancellationToken); if (tryCreate.Succeeded) { IDocumentQueryExecutionComponent executionContext = tryCreate.Result; Assert.IsTrue(!executionContext.IsDone); // Read all the pages from both splits List <ToDoItem> itemsRead = new List <ToDoItem>(); QueryResponseCore?failure = null; while (!executionContext.IsDone) { QueryResponseCore queryResponse = await executionContext.DrainAsync( maxPageSize, this.cancellationToken); if (queryResponse.IsSuccess) { string responseContinuationToken = queryResponse.ContinuationToken; foreach (CosmosElement element in queryResponse.CosmosElements) { string jsonValue = element.ToString(); ToDoItem item = JsonConvert.DeserializeObject <ToDoItem>(jsonValue); itemsRead.Add(item); } } else { Assert.IsNull(failure, "There should only be one error"); failure = queryResponse; } } Assert.IsNotNull(failure); Assert.AreEqual((HttpStatusCode)429, failure.Value.StatusCode); Assert.IsNotNull(failure.Value.CosmosException.ToString()); Assert.AreEqual(0 /*We don't get any items, since we don't buffer the failure anymore*/, itemsRead.Count); //CollectionAssert.AreEqual(allItems.ToList(), itemsRead, new ToDoItemComparer()); } else { QueryResponseCore queryResponseCore = QueryResponseFactory.CreateFromException(tryCreate.Exception); Assert.AreEqual((HttpStatusCode)429, queryResponseCore.StatusCode); } } }
public static async Task <TryCatch <CosmosQueryExecutionContext> > TryCreateAsync( ExecutionEnvironment executionEnvironment, CosmosQueryContext queryContext, CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams initParams, string requestContinuationToken, CancellationToken cancellationToken) { if (queryContext == null) { throw new ArgumentNullException(nameof(initParams)); } cancellationToken.ThrowIfCancellationRequested(); QueryInfo queryInfo = initParams.PartitionedQueryExecutionInfo.QueryInfo; int initialPageSize = initParams.InitialPageSize; if (queryInfo.HasGroupBy) { // The query will block until all groupings are gathered so we might as well speed up the process. initParams = new CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams( sqlQuerySpec: initParams.SqlQuerySpec, collectionRid: initParams.CollectionRid, partitionedQueryExecutionInfo: initParams.PartitionedQueryExecutionInfo, partitionKeyRanges: initParams.PartitionKeyRanges, initialPageSize: int.MaxValue, maxConcurrency: initParams.MaxConcurrency, maxItemCount: int.MaxValue, maxBufferedItemCount: initParams.MaxBufferedItemCount); } async Task <TryCatch <IDocumentQueryExecutionComponent> > tryCreateOrderByComponentAsync(string continuationToken) { return((await CosmosOrderByItemQueryExecutionContext.TryCreateAsync( queryContext, initParams, continuationToken, cancellationToken)).Try <IDocumentQueryExecutionComponent>(component => component)); } async Task <TryCatch <IDocumentQueryExecutionComponent> > tryCreateParallelComponentAsync(string continuationToken) { return((await CosmosParallelItemQueryExecutionContext.TryCreateAsync( queryContext, initParams, continuationToken, cancellationToken)).Try <IDocumentQueryExecutionComponent>(component => component)); } Func <string, Task <TryCatch <IDocumentQueryExecutionComponent> > > tryCreatePipelineAsync; if (queryInfo.HasOrderBy) { tryCreatePipelineAsync = tryCreateOrderByComponentAsync; } else { tryCreatePipelineAsync = tryCreateParallelComponentAsync; } if (queryInfo.HasAggregates && !queryInfo.HasGroupBy) { Func <string, Task <TryCatch <IDocumentQueryExecutionComponent> > > tryCreateSourceAsync = tryCreatePipelineAsync; tryCreatePipelineAsync = async(continuationToken) => { return(await AggregateDocumentQueryExecutionComponent.TryCreateAsync( executionEnvironment, queryInfo.Aggregates, queryInfo.GroupByAliasToAggregateType, queryInfo.GroupByAliases, queryInfo.HasSelectValue, continuationToken, tryCreateSourceAsync)); }; } if (queryInfo.HasDistinct) { Func <string, Task <TryCatch <IDocumentQueryExecutionComponent> > > tryCreateSourceAsync = tryCreatePipelineAsync; tryCreatePipelineAsync = async(continuationToken) => { return(await DistinctDocumentQueryExecutionComponent.TryCreateAsync( executionEnvironment, continuationToken, tryCreateSourceAsync, queryInfo.DistinctType)); }; } if (queryInfo.HasGroupBy) { Func <string, Task <TryCatch <IDocumentQueryExecutionComponent> > > tryCreateSourceAsync = tryCreatePipelineAsync; tryCreatePipelineAsync = async(continuationToken) => { return(await GroupByDocumentQueryExecutionComponent.TryCreateAsync( executionEnvironment, continuationToken, tryCreateSourceAsync, queryInfo.GroupByAliasToAggregateType, queryInfo.GroupByAliases, queryInfo.HasSelectValue)); }; } if (queryInfo.HasOffset) { Func <string, Task <TryCatch <IDocumentQueryExecutionComponent> > > tryCreateSourceAsync = tryCreatePipelineAsync; tryCreatePipelineAsync = async(continuationToken) => { return(await SkipDocumentQueryExecutionComponent.TryCreateAsync( queryInfo.Offset.Value, continuationToken, tryCreateSourceAsync)); }; } if (queryInfo.HasLimit) { Func <string, Task <TryCatch <IDocumentQueryExecutionComponent> > > tryCreateSourceAsync = tryCreatePipelineAsync; tryCreatePipelineAsync = async(continuationToken) => { return(await TakeDocumentQueryExecutionComponent.TryCreateLimitDocumentQueryExecutionComponentAsync( queryInfo.Limit.Value, continuationToken, tryCreateSourceAsync)); }; } if (queryInfo.HasTop) { Func <string, Task <TryCatch <IDocumentQueryExecutionComponent> > > tryCreateSourceAsync = tryCreatePipelineAsync; tryCreatePipelineAsync = async(continuationToken) => { return(await TakeDocumentQueryExecutionComponent.TryCreateTopDocumentQueryExecutionComponentAsync( queryInfo.Top.Value, continuationToken, tryCreateSourceAsync)); }; } return((await tryCreatePipelineAsync(requestContinuationToken)) .Try <CosmosQueryExecutionContext>((source) => new PipelinedDocumentQueryExecutionContext(source, initialPageSize))); }
public async Task TestCosmosOrderByQueryExecutionContextWithEmptyPagesAndSplitAsync(bool createInitialContinuationToken) { int maxPageSize = 5; List <MockPartitionResponse[]> mockResponsesScenario = MockQueryFactory.GetSplitScenarios(); Mock <CosmosQueryClient> mockQueryClient = new Mock <CosmosQueryClient>(); foreach (MockPartitionResponse[] mockResponse in mockResponsesScenario) { string initialContinuationToken = null; string fullConitnuationToken = null; if (createInitialContinuationToken) { ToDoItem itemToRepresentPreviousQuery = ToDoItem.CreateItems( 1, "itemToRepresentPreviousQuery", MockQueryFactory.DefaultCollectionRid).First(); initialContinuationToken = $" - RID:{itemToRepresentPreviousQuery._rid} ==#RT:1#TRC:1"; CompositeContinuationToken compositeContinuation = new CompositeContinuationToken() { Range = new Documents.Routing.Range <string>( min: MockQueryFactory.DefaultPartitionKeyRange.MinInclusive, max: MockQueryFactory.DefaultPartitionKeyRange.MaxExclusive, isMaxInclusive: false, isMinInclusive: true), Token = initialContinuationToken }; List <OrderByItem> orderByItems = new List <OrderByItem>() { new OrderByItem(CosmosObject.CreateFromBuffer(Encoding.UTF8.GetBytes("{\"item\":\"2c4ce711-13c3-4c93-817c-49287b71b6c3\"}"))) }; OrderByContinuationToken orderByContinuationToken = new OrderByContinuationToken( queryClient: mockQueryClient.Object, compositeContinuationToken: compositeContinuation, orderByItems: orderByItems, rid: itemToRepresentPreviousQuery._rid, skipCount: 0, filter: null); fullConitnuationToken = JsonConvert.SerializeObject(new OrderByContinuationToken[] { orderByContinuationToken }); } IList <ToDoItem> allItems = MockQueryFactory.GenerateAndMockResponse( mockQueryClient, isOrderByQuery: true, sqlQuerySpec: MockQueryFactory.DefaultQuerySpec, containerRid: MockQueryFactory.DefaultCollectionRid, initContinuationToken: initialContinuationToken, maxPageSize: maxPageSize, mockResponseForSinglePartition: mockResponse, cancellationTokenForMocks: this.cancellationToken); // Order by drains the partitions until it finds an item // If there are no items then it's not possible to have a continuation token if (allItems.Count == 0 && createInitialContinuationToken) { continue; } CosmosQueryContext context = MockQueryFactory.CreateContext( mockQueryClient.Object); QueryInfo queryInfo = new QueryInfo() { OrderBy = new SortOrder[] { SortOrder.Ascending }, OrderByExpressions = new string[] { "id" } }; CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams initParams = new CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams( sqlQuerySpec: MockQueryFactory.DefaultQuerySpec, collectionRid: MockQueryFactory.DefaultCollectionRid, partitionedQueryExecutionInfo: new PartitionedQueryExecutionInfo() { QueryInfo = queryInfo }, partitionKeyRanges: new List <PartitionKeyRange>() { MockQueryFactory.DefaultPartitionKeyRange }, initialPageSize: maxPageSize, maxConcurrency: null, maxItemCount: maxPageSize, maxBufferedItemCount: null); CosmosOrderByItemQueryExecutionContext executionContext = (await CosmosOrderByItemQueryExecutionContext.TryCreateAsync( context, initParams, fullConitnuationToken, this.cancellationToken)).Result; // For order by it will drain all the pages till it gets a value. if (allItems.Count == 0) { Assert.IsTrue(executionContext.IsDone); continue; } Assert.IsTrue(!executionContext.IsDone); // Read all the pages from both splits List <ToDoItem> itemsRead = new List <ToDoItem>(); while (!executionContext.IsDone) { QueryResponseCore queryResponse = await executionContext.DrainAsync( maxPageSize, this.cancellationToken); string responseContinuationToken = queryResponse.ContinuationToken; foreach (CosmosElement element in queryResponse.CosmosElements) { string jsonValue = element.ToString(); ToDoItem item = JsonConvert.DeserializeObject <ToDoItem>(jsonValue); itemsRead.Add(item); } } Assert.AreEqual(allItems.Count, itemsRead.Count); CollectionAssert.AreEqual(allItems.ToList(), itemsRead, new ToDoItemComparer()); } }