public async Task SharedThroughputTests() { string databaseId = Guid.NewGuid().ToString(); int throughput = 10000; DatabaseResponse createResponse = await this.CreateDatabaseHelper(databaseId, databaseExists : false, throughput : throughput); Assert.AreEqual(HttpStatusCode.Created, createResponse.StatusCode); Cosmos.Database cosmosDatabase = createResponse; int? readThroughput = await cosmosDatabase.ReadThroughputAsync(); Assert.AreEqual(throughput, readThroughput); string containerId = Guid.NewGuid().ToString(); string partitionPath = "/users"; ContainerResponse containerResponse = await cosmosDatabase.CreateContainerAsync(containerId, partitionPath); Assert.AreEqual(HttpStatusCode.Created, containerResponse.StatusCode); Container container = containerResponse; try { readThroughput = await((ContainerCore)container).ReadThroughputAsync(); Assert.Fail("Should through not found exception as throughput is not configured"); } catch (CosmosException exception) { Assert.AreEqual(HttpStatusCode.NotFound, exception.StatusCode); } await container.DeleteContainerAsync(); await cosmosDatabase.DeleteAsync(); }
public async Task ValidateCurrentWriteQuorumAndReplicaSetHeader() { CosmosClient client = TestCommon.CreateCosmosClient(false); Cosmos.Database db = null; try { db = await client.CreateDatabaseAsync(Guid.NewGuid().ToString()); PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition { Paths = new System.Collections.ObjectModel.Collection <string>(new[] { "/id" }), Kind = PartitionKind.Hash }; ContainerProperties containerSetting = new ContainerProperties() { Id = Guid.NewGuid().ToString(), PartitionKey = partitionKeyDefinition }; Container coll = await db.CreateContainerAsync(containerSetting); Document documentDefinition = new Document { Id = Guid.NewGuid().ToString() }; ItemResponse <Document> docResult = await coll.CreateItemAsync <Document>(documentDefinition); Assert.IsTrue(int.Parse(docResult.Headers[WFConstants.BackendHeaders.CurrentWriteQuorum], CultureInfo.InvariantCulture) > 0); Assert.IsTrue(int.Parse(docResult.Headers[WFConstants.BackendHeaders.CurrentReplicaSetSize], CultureInfo.InvariantCulture) > 0); } finally { await db.DeleteAsync(); } }
private static void InitializeSharedThroughputContainer() { CosmosClient client = TestCommon.CreateCosmosClient(); Cosmos.Database db = client.CreateDatabaseAsync(string.Format("Shared_{0}", Guid.NewGuid().ToString("N")), throughput: 20000).GetAwaiter().GetResult().Database; for (int index = 0; index < 5; index++) { ContainerResponse containerResponse = db.CreateContainerAsync( new ContainerProperties { Id = Guid.NewGuid().ToString(), PartitionKey = BatchTestBase.PartitionKeyDefinition }) .GetAwaiter().GetResult(); Assert.AreEqual(true, bool.Parse(containerResponse.Headers.Get(WFConstants.BackendHeaders.ShareThroughput))); if (index == 2) { BatchTestBase.SharedThroughputContainer = containerResponse.Container; } } BatchTestBase.SharedThroughputDatabase = db; }
public async Task SharedThroughputTests() { string databaseId = Guid.NewGuid().ToString(); int throughput = 10000; DatabaseResponse createResponse = await this.CreateDatabaseHelper(databaseId, databaseExists : false, throughput : throughput); Assert.AreEqual(HttpStatusCode.Created, createResponse.StatusCode); Cosmos.Database cosmosDatabase = createResponse; int? readThroughput = await((DatabaseCore)cosmosDatabase).ReadProvisionedThroughputAsync(); Assert.AreEqual(throughput, readThroughput); string containerId = Guid.NewGuid().ToString(); string partitionPath = "/users"; ContainerResponse containerResponse = await cosmosDatabase.CreateContainerAsync(containerId, partitionPath); Assert.AreEqual(HttpStatusCode.Created, containerResponse.StatusCode); Container container = containerResponse; readThroughput = await((ContainerCore)container).ReadProvisionedThroughputAsync(); Assert.IsNull(readThroughput); await container.DeleteContainerAsync(); await cosmosDatabase.DeleteAsync(); }
public async Task ReadReplaceThroughputResponseTests() { string databaseId = Guid.NewGuid().ToString(); int throughput = 10000; DatabaseResponse createResponse = await this.CreateDatabaseHelper(databaseId, databaseExists : false, throughput : throughput); Assert.AreEqual(HttpStatusCode.Created, createResponse.StatusCode); Cosmos.Database cosmosDatabase = createResponse; ThroughputResponse readThroughputResponse = await cosmosDatabase.ReadThroughputAsync(new RequestOptions()); Assert.IsNotNull(readThroughputResponse); Assert.IsNotNull(readThroughputResponse.Resource); Assert.IsNotNull(readThroughputResponse.MinThroughput); Assert.IsNotNull(readThroughputResponse.Resource.Throughput); Assert.AreEqual(throughput, readThroughputResponse.Resource.Throughput.Value); // Implicit ThroughputProperties throughputProperties = await cosmosDatabase.ReadThroughputAsync(new RequestOptions()); Assert.IsNotNull(throughputProperties); Assert.AreEqual(throughput, throughputProperties.Throughput); // Simple API int?readThroughput = await cosmosDatabase.ReadThroughputAsync(); Assert.AreEqual(throughput, readThroughput); string containerId = Guid.NewGuid().ToString(); string partitionPath = "/users"; ContainerResponse containerResponse = await cosmosDatabase.CreateContainerAsync(containerId, partitionPath); Assert.AreEqual(HttpStatusCode.Created, containerResponse.StatusCode); ThroughputResponse replaceThroughputResponse = await cosmosDatabase.ReplaceThroughputAsync(readThroughputResponse.Resource.Throughput.Value + 1000); Assert.IsNotNull(replaceThroughputResponse); Assert.IsNotNull(replaceThroughputResponse.Resource); Assert.AreEqual(readThroughputResponse.Resource.Throughput.Value + 1000, replaceThroughputResponse.Resource.Throughput.Value); Container container = containerResponse; try { readThroughputResponse = await container.ReadThroughputAsync(new RequestOptions()); Assert.Fail("Should through not found exception as throughput is not configured"); } catch (CosmosException exception) { Assert.AreEqual(HttpStatusCode.NotFound, exception.StatusCode); } await container.DeleteContainerAsync(); await cosmosDatabase.DeleteAsync(); }
public async Task TransportExceptionValidationTest(bool injectCpuMonitor) { CosmosClient cosmosClient = TestCommon.CreateCosmosClient( builder => { builder.WithTransportClientHandlerFactory(transportClient => new TransportClientWrapper( transportClient, TransportWrapperTests.ThrowTransportExceptionOnItemOperation, injectCpuMonitor)); }); Cosmos.Database database = await cosmosClient.CreateDatabaseAsync(Guid.NewGuid().ToString()); Container container = await database.CreateContainerAsync(Guid.NewGuid().ToString(), "/id"); try { TestPayload payload1 = await container.CreateItemAsync <TestPayload>(new TestPayload { id = "bad" }, new Cosmos.PartitionKey("bad")); Assert.Fail("Create item should fail with TransportException"); } catch (CosmosException ce) { this.ValidateTransportException(ce, injectCpuMonitor); } try { FeedIterator <TestPayload> feedIterator = container.GetItemQueryIterator <TestPayload>("select * from T where T.Random = 19827 "); await feedIterator.ReadNextAsync(); Assert.Fail("Create item should fail with TransportException"); } catch (CosmosException ce) { this.ValidateTransportException(ce, injectCpuMonitor); } using (ResponseMessage responseMessage = await container.CreateItemStreamAsync( TestCommon.SerializerCore.ToStream(new TestPayload { id = "bad" }), new Cosmos.PartitionKey("bad"))) { this.ValidateTransportException(responseMessage); } FeedIterator streamIterator = container.GetItemQueryStreamIterator("select * from T where T.Random = 19827 "); using (ResponseMessage responseMessage = await streamIterator.ReadNextAsync()) { this.ValidateTransportException(responseMessage); } }
public async Task HttpClientConnectionLimitTest() { int gatewayConnectionLimit = 1; IReadOnlyList <string> excludeConnections = GetActiveConnections(); CosmosClient cosmosClient = new CosmosClient( ConfigurationManager.AppSettings["GatewayEndpoint"], ConfigurationManager.AppSettings["MasterKey"], new CosmosClientOptions { ApplicationName = "test", GatewayModeMaxConnectionLimit = gatewayConnectionLimit, ConnectionMode = ConnectionMode.Gateway, ConnectionProtocol = Protocol.Https } ); FieldInfo httpClient = cosmosClient.DocumentClient.GetType().GetField("httpClient", BindingFlags.NonPublic | BindingFlags.Instance); CosmosHttpClient cosmosHttpClient = (CosmosHttpClient)httpClient.GetValue(cosmosClient.DocumentClient); HttpClientHandler httpClientHandler = (HttpClientHandler)cosmosHttpClient.HttpMessageHandler; Assert.AreEqual(gatewayConnectionLimit, httpClientHandler.MaxConnectionsPerServer); Cosmos.Database database = await cosmosClient.CreateDatabaseAsync(Guid.NewGuid().ToString()); Container container = await database.CreateContainerAsync( "TestConnections", "/pk", throughput : 20000); List <Task> creates = new List <Task>(); for (int i = 0; i < 100; i++) { creates.Add(container.CreateItemAsync <dynamic>(new { id = Guid.NewGuid().ToString(), pk = Guid.NewGuid().ToString() })); } await Task.WhenAll(creates); // Verify the handler still exists after client warm up //Assert.AreEqual(gatewayConnectionLimit, httpClientHandler.MaxConnectionsPerServer); IReadOnlyList <string> afterConnections = GetActiveConnections(); // Clean up the database and container await database.DeleteAsync(); int connectionDiff = afterConnections.Count - excludeConnections.Count; Assert.IsTrue(connectionDiff <= gatewayConnectionLimit, $"Connection before : {excludeConnections.Count}, after {afterConnections.Count}"); }
public async Task HttpClientConnectionLimitTest() { int gatewayConnectionLimit = 1; IReadOnlyList <string> excludeConnections = GetActiveConnections(); using (CosmosClient cosmosClient = new CosmosClient( ConfigurationManager.AppSettings["GatewayEndpoint"], ConfigurationManager.AppSettings["MasterKey"], new CosmosClientOptions { ApplicationName = "test", GatewayModeMaxConnectionLimit = gatewayConnectionLimit, ConnectionMode = ConnectionMode.Gateway, ConnectionProtocol = Protocol.Https } )) { CosmosHttpClient cosmosHttpClient = cosmosClient.DocumentClient.httpClient; HttpClientHandler httpClientHandler = (HttpClientHandler)cosmosHttpClient.HttpMessageHandler; Assert.AreEqual(gatewayConnectionLimit, httpClientHandler.MaxConnectionsPerServer); Cosmos.Database database = await cosmosClient.CreateDatabaseAsync(Guid.NewGuid().ToString()); Container container = await database.CreateContainerAsync( "TestConnections", "/pk", throughput : 20000); List <Task> creates = new List <Task>(); for (int i = 0; i < 100; i++) { creates.Add(container.CreateItemAsync <dynamic>(new { id = Guid.NewGuid().ToString(), pk = Guid.NewGuid().ToString() })); } await Task.WhenAll(creates); // Clean up the database and container await database.DeleteAsync(); } IReadOnlyList <string> afterConnections = GetActiveConnections(); int connectionDiff = afterConnections.Count - excludeConnections.Count; Assert.IsTrue(connectionDiff <= gatewayConnectionLimit, $"Connection before : {excludeConnections.Count}, after {afterConnections.Count};" + $"Before connections: {JsonConvert.SerializeObject(excludeConnections)}; After connections: {JsonConvert.SerializeObject(afterConnections)}"); }
public static Func <bool, IQueryable <Data> > GenerateSimpleCosmosData( Cosmos.Database cosmosDatabase ) { const int DocumentCount = 10; PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition { Paths = new System.Collections.ObjectModel.Collection <string>(new[] { "/Pk" }), Kind = PartitionKind.Hash }; Container container = cosmosDatabase.CreateContainerAsync(new ContainerProperties { Id = Guid.NewGuid().ToString(), PartitionKey = partitionKeyDefinition }).Result; int seed = DateTime.Now.Millisecond; Random random = new Random(seed); Debug.WriteLine("Random seed: {0}", seed); List <Data> testData = new List <Data>(); for (int index = 0; index < DocumentCount; index++) { Data dataEntry = new Data() { Id = Guid.NewGuid().ToString(), Number = random.Next(-10000, 10000), Flag = index % 2 == 0 ? true : false, Multiples = new int[] { index, index * 2, index * 3, index * 4 }, Pk = "Test" }; Data response = container.CreateItemAsync <Data>(dataEntry, new Cosmos.PartitionKey(dataEntry.Pk)).Result; testData.Add(dataEntry); } FeedOptions feedOptions = new FeedOptions() { EnableScanInQuery = true, EnableCrossPartitionQuery = true }; var query = container.GetItemLinqQueryable <Data>(allowSynchronousQueryExecution: true); // To cover both query against backend and queries on the original data using LINQ nicely, // the LINQ expression should be written once and they should be compiled and executed against the two sources. // That is done by using Func that take a boolean Func. The parameter of the Func indicate whether the Cosmos DB query // or the data list should be used. When a test is executed, the compiled LINQ expression would pass different values // to this getQuery method. IQueryable <Data> getQuery(bool useQuery) => useQuery ? query : testData.AsQueryable(); return(getQuery); }
public async Task TransportInterceptorContractTest() { CosmosClient cosmosClient = TestCommon.CreateCosmosClient( builder => { builder.WithTransportClientHandlerFactory(transportClient => new TransportClientWrapper(transportClient, TransportWrapperTests.Interceptor)); }); Cosmos.Database database = await cosmosClient.CreateDatabaseAsync(Guid.NewGuid().ToString()); Container container = await database.CreateContainerAsync(Guid.NewGuid().ToString(), "/id"); string id1 = Guid.NewGuid().ToString(); TestPayload payload1 = await container.CreateItemAsync <TestPayload>(new TestPayload { id = id1 }); payload1 = await container.ReadItemAsync <TestPayload>(id1, new Cosmos.PartitionKey(id1)); }
public async Task TestInitialize() { PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition { Paths = new System.Collections.ObjectModel.Collection <string>(new[] { "/Pk" }), Kind = PartitionKind.Hash }; // The test collection should have range index on string properties // for the orderby tests var newCol = new ContainerProperties() { Id = Guid.NewGuid().ToString(), PartitionKey = partitionKeyDefinition, IndexingPolicy = new Microsoft.Azure.Cosmos.IndexingPolicy() { IncludedPaths = new System.Collections.ObjectModel.Collection <Microsoft.Azure.Cosmos.IncludedPath>() { new Microsoft.Azure.Cosmos.IncludedPath() { Path = "/*", Indexes = new System.Collections.ObjectModel.Collection <Microsoft.Azure.Cosmos.Index>() { Microsoft.Azure.Cosmos.Index.Range(Microsoft.Azure.Cosmos.DataType.Number, -1), Microsoft.Azure.Cosmos.Index.Range(Microsoft.Azure.Cosmos.DataType.String, -1) } } } } }; testCollection = await testDb.CreateContainerAsync(newCol); const int Records = 100; const int MaxStringLength = 100; Func <Random, Datum> createDataFunc = random => { var obj = new Datum(); obj.Id = Guid.NewGuid().ToString(); obj.Pk = "Test"; obj.JsonProperty = random.NextDouble() < 0.3 ? "Hello" : LinqTestsCommon.RandomString(random, random.Next(MaxStringLength)); obj.JsonPropertyAndDataMember = random.NextDouble() < 0.3 ? "Hello" : LinqTestsCommon.RandomString(random, random.Next(MaxStringLength)); obj.DataMember = random.NextDouble() < 0.3 ? "Hello" : LinqTestsCommon.RandomString(random, random.Next(MaxStringLength)); obj.Default = random.NextDouble() < 0.3 ? "Hello" : LinqTestsCommon.RandomString(random, random.Next(MaxStringLength)); return(obj); }; getQuery = LinqTestsCommon.GenerateTestCosmosData(createDataFunc, Records, testCollection); }
public async Task HttpClientFactorySmokeTest() { HttpClient client = new HttpClient(); Mock <Func <HttpClient> > factory = new Mock <Func <HttpClient> >(); factory.Setup(f => f()).Returns(client); CosmosClient cosmosClient = new CosmosClient( ConfigurationManager.AppSettings["GatewayEndpoint"], ConfigurationManager.AppSettings["MasterKey"], new CosmosClientOptions { ApplicationName = "test", ConnectionMode = ConnectionMode.Gateway, ConnectionProtocol = Protocol.Https, HttpClientFactory = factory.Object } ); string someId = Guid.NewGuid().ToString(); Cosmos.Database database = null; try { database = await cosmosClient.CreateDatabaseAsync(someId); Cosmos.Container container = await database.CreateContainerAsync(Guid.NewGuid().ToString(), "/id"); await container.CreateItemAsync <dynamic>(new { id = someId }); await container.ReadItemAsync <dynamic>(someId, new Cosmos.PartitionKey(someId)); await container.DeleteItemAsync <dynamic>(someId, new Cosmos.PartitionKey(someId)); await container.DeleteContainerAsync(); Mock.Get(factory.Object).Verify(f => f(), Times.Once); } finally { if (database != null) { await database.DeleteAsync(); } } }
public async Task QueryPlanRetryTimeoutTestAsync() { HttpClientHandlerHelper httpClientHandler = new HttpClientHandlerHelper(); using (CosmosClient client = TestCommon.CreateCosmosClient(builder => builder .WithConnectionModeGateway() .WithHttpClientFactory(() => new HttpClient(httpClientHandler)))) { Cosmos.Database database = await client.CreateDatabaseAsync(Guid.NewGuid().ToString()); ContainerInternal container = (ContainerInternal)await database.CreateContainerAsync(Guid.NewGuid().ToString(), "/pk"); Container gatewayQueryPlanContainer = new ContainerInlineCore( client.ClientContext, (DatabaseInternal)database, container.Id, new DisableServiceInterop(client.ClientContext, container)); bool isQueryRequestFound = false; httpClientHandler.RequestCallBack = (request, cancellationToken) => { if (request.Headers.TryGetValues(HttpConstants.HttpHeaders.IsQueryPlanRequest, out IEnumerable <string> isQueryPlan) && isQueryPlan.FirstOrDefault() == bool.TrueString) { Assert.IsFalse(isQueryRequestFound, "Should only call get query plan once."); Assert.AreNotEqual(cancellationToken, default); isQueryRequestFound = true; } }; using FeedIterator <JObject> iterator = gatewayQueryPlanContainer.GetItemQueryIterator <JObject>("select * From T order by T.status"); FeedResponse <JObject> response = await iterator.ReadNextAsync(); Assert.IsTrue(isQueryRequestFound, "Query plan call back was not called."); string diagnostics = response.Diagnostics.ToString(); JObject parsedDiagnostics = JObject.Parse(diagnostics); JToken contextList = parsedDiagnostics["Context"]; Assert.IsNotNull(contextList.First(x => x["Id"]?.ToString() == "CreateQueryPipeline")); Assert.IsNotNull(contextList.First(x => x["Id"]?.ToString() == "Microsoft.Azure.Cosmos.GatewayStoreModel")); Assert.IsNotNull(contextList.First(x => x["Id"]?.ToString() == "SendHttpHelperAsync:" + nameof(HttpTimeoutPolicyControlPlaneRetriableHotPath))); await database.DeleteStreamAsync(); } }
private static async Task RoundTripWithLocal(Cosmos.IndexingPolicy indexingPolicy) { PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition { Paths = new System.Collections.ObjectModel.Collection <string>(new[] { "/id" }), Kind = PartitionKind.Hash }; ContainerProperties containerSetting = new ContainerProperties() { Id = Guid.NewGuid().ToString(), IndexingPolicy = indexingPolicy, PartitionKey = partitionKeyDefinition }; Cosmos.Database cosmosDatabase = await cosmosClient.CreateDatabaseIfNotExistsAsync(IndexingPolicyTests.database.Id); ContainerResponse cosmosContainerResponse = await cosmosDatabase.CreateContainerAsync(containerSetting); Assert.IsTrue(IndexingPolicyTests.indexingPolicyEqualityComparer.Equals(indexingPolicy, containerSetting.IndexingPolicy)); }
public async Task ReadReplaceThroughputResponseTests() { string databaseId = Guid.NewGuid().ToString(); int throughput = 10000; DatabaseResponse createResponse = await this.CreateDatabaseHelper(databaseId, databaseExists : false, throughput : throughput); Assert.AreEqual(HttpStatusCode.Created, createResponse.StatusCode); Cosmos.Database cosmosDatabase = createResponse; ThroughputResponse readThroughputResponse = await cosmosDatabase.ReadThroughputAsync(); Assert.IsNotNull(readThroughputResponse); Assert.IsNotNull(readThroughputResponse.Resource); Assert.IsNotNull(readThroughputResponse.MinThroughput); Assert.IsNotNull(readThroughputResponse.Resource.Throughput); Assert.AreEqual(throughput, readThroughputResponse.Resource.Throughput.Value); string containerId = Guid.NewGuid().ToString(); string partitionPath = "/users"; ContainerResponse containerResponse = await cosmosDatabase.CreateContainerAsync(containerId, partitionPath); Assert.AreEqual(HttpStatusCode.Created, containerResponse.StatusCode); ThroughputResponse replaceThroughputResponse = await cosmosDatabase.ReplaceThroughputAsync(readThroughputResponse.Resource.Throughput.Value + 1000); Assert.IsNotNull(replaceThroughputResponse); Assert.IsNotNull(replaceThroughputResponse.Resource); Assert.AreEqual(readThroughputResponse.Resource.Throughput.Value + 1000, replaceThroughputResponse.Resource.Throughput.Value); Container container = containerResponse; readThroughputResponse = await container.ReadThroughputAsync(); Assert.IsNull(readThroughputResponse.Resource); await container.DeleteContainerAsync(); await cosmosDatabase.DeleteAsync(); }
public async Task ReadReplaceThroughputResponseTests() { int toStreamCount = 0; int fromStreamCount = 0; CosmosSerializerHelper mockJsonSerializer = new CosmosSerializerHelper( null, (x) => fromStreamCount++, (x) => toStreamCount++); //Create a new cosmos client with the mocked cosmos json serializer CosmosClient client = TestCommon.CreateCosmosClient( (cosmosClientBuilder) => cosmosClientBuilder.WithCustomSerializer(mockJsonSerializer)); int databaseThroughput = 10000; Cosmos.Database databaseNoThroughput = await client.CreateDatabaseAsync(Guid.NewGuid().ToString(), null); Cosmos.Database databaseWithThroughput = await client.CreateDatabaseAsync(Guid.NewGuid().ToString(), databaseThroughput, null); string containerId = Guid.NewGuid().ToString(); string partitionPath = "/users"; Container containerNoThroughput = await databaseWithThroughput.CreateContainerAsync(containerId, partitionPath, throughput : null); try { await containerNoThroughput.ReadThroughputAsync(new RequestOptions()); Assert.Fail("Should through not found exception as throughput is not configured"); } catch (CosmosException exception) { Assert.AreEqual(HttpStatusCode.NotFound, exception.StatusCode); } try { await containerNoThroughput.ReplaceThroughputAsync(2000, new RequestOptions()); Assert.Fail("Should through not found exception as throughput is not configured"); } catch (CosmosException exception) { Assert.AreEqual(HttpStatusCode.NotFound, exception.StatusCode); } int containerThroughput = 1000; Container container = await databaseNoThroughput.CreateContainerAsync(Guid.NewGuid().ToString(), "/id", throughput : containerThroughput); int?containerResponseThroughput = await container.ReadThroughputAsync(); Assert.AreEqual(containerThroughput, containerResponseThroughput); ThroughputResponse containerThroughputResponse = await container.ReadThroughputAsync(new RequestOptions()); Assert.IsNotNull(containerThroughputResponse); Assert.IsNotNull(containerThroughputResponse.Resource); Assert.IsNotNull(containerThroughputResponse.MinThroughput); Assert.IsNotNull(containerThroughputResponse.Resource.Throughput); Assert.AreEqual(containerThroughput, containerThroughputResponse.Resource.Throughput.Value); containerThroughput += 500; containerThroughputResponse = await container.ReplaceThroughputAsync(containerThroughput, new RequestOptions()); Assert.IsNotNull(containerThroughputResponse); Assert.IsNotNull(containerThroughputResponse.Resource); Assert.IsNotNull(containerThroughputResponse.Resource.Throughput); Assert.AreEqual(containerThroughput, containerThroughputResponse.Resource.Throughput.Value); Assert.AreEqual(0, toStreamCount, "Custom serializer to stream should not be used for offer operations"); Assert.AreEqual(0, fromStreamCount, "Custom serializer from stream should not be used for offer operations"); await databaseNoThroughput.DeleteAsync(); }
public async Task ValidateAzureKeyCredentialDirectModeUpdateAsync() { string authKey = ConfigurationManager.AppSettings["MasterKey"]; string endpoint = ConfigurationManager.AppSettings["GatewayEndpoint"]; AzureKeyCredential masterKeyCredential = new AzureKeyCredential(authKey); using (CosmosClient client = new CosmosClient( endpoint, masterKeyCredential)) { string databaseName = Guid.NewGuid().ToString(); try { Cosmos.Database database = client.GetDatabase(databaseName); ResponseMessage responseMessage = await database.ReadStreamAsync(); Assert.AreEqual(HttpStatusCode.NotFound, responseMessage.StatusCode); { // Random key: Next set of actions are expected to fail => 401 (UnAuthorized) masterKeyCredential.Update(Convert.ToBase64String(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString()))); responseMessage = await database.ReadStreamAsync(); Assert.AreEqual(HttpStatusCode.Unauthorized, responseMessage.StatusCode); string diagnostics = responseMessage.Diagnostics.ToString(); Assert.IsTrue(diagnostics.Contains("AuthProvider LifeSpan InSec"), diagnostics.ToString()); } { // Resetting back to master key => 404 (NotFound) masterKeyCredential.Update(authKey); responseMessage = await database.ReadStreamAsync(); Assert.AreEqual(HttpStatusCode.NotFound, responseMessage.StatusCode); } // Test with resource token interchageability masterKeyCredential.Update(authKey); database = await client.CreateDatabaseAsync(databaseName); string containerId = Guid.NewGuid().ToString(); ContainerResponse containerResponse = await database.CreateContainerAsync(containerId, "/id"); Assert.AreEqual(HttpStatusCode.Created, containerResponse.StatusCode); { // Resource token with ALL permissoin's string userId = Guid.NewGuid().ToString(); UserResponse userResponse = await database.CreateUserAsync(userId); Cosmos.User user = userResponse.User; Assert.AreEqual(HttpStatusCode.Created, userResponse.StatusCode); Assert.AreEqual(userId, user.Id); string permissionId = Guid.NewGuid().ToString(); PermissionProperties permissionProperties = new PermissionProperties(permissionId, Cosmos.PermissionMode.All, client.GetContainer(databaseName, containerId)); PermissionResponse permissionResponse = await database.GetUser(userId).CreatePermissionAsync(permissionProperties); Assert.AreEqual(HttpStatusCode.Created, permissionResponse.StatusCode); Assert.AreEqual(permissionId, permissionResponse.Resource.Id); Assert.AreEqual(Cosmos.PermissionMode.All, permissionResponse.Resource.PermissionMode); Assert.IsNotNull(permissionResponse.Resource.Token); SelflinkValidator.ValidatePermissionSelfLink(permissionResponse.Resource.SelfLink); // Valdiate ALL on contianer masterKeyCredential.Update(permissionResponse.Resource.Token); ToDoActivity item = ToDoActivity.CreateRandomToDoActivity(); Cosmos.Container container = client.GetContainer(databaseName, containerId); responseMessage = await container.ReadContainerStreamAsync(); Assert.AreEqual(HttpStatusCode.OK, responseMessage.StatusCode); responseMessage = await container.CreateItemStreamAsync(TestCommon.SerializerCore.ToStream(item), new Cosmos.PartitionKey(item.id)); Assert.AreEqual(HttpStatusCode.Created, responseMessage.StatusCode); // Read Only resorce token } // Reset to master key for new permission creation masterKeyCredential.Update(authKey); { // Resource token with Read-ONLY permissoin's string userId = Guid.NewGuid().ToString(); UserResponse userResponse = await database.CreateUserAsync(userId); Cosmos.User user = userResponse.User; Assert.AreEqual(HttpStatusCode.Created, userResponse.StatusCode); Assert.AreEqual(userId, user.Id); string permissionId = Guid.NewGuid().ToString(); PermissionProperties permissionProperties = new PermissionProperties(permissionId, Cosmos.PermissionMode.Read, client.GetContainer(databaseName, containerId)); PermissionResponse permissionResponse = await database.GetUser(userId).CreatePermissionAsync(permissionProperties); //Backend returns Created instead of OK Assert.AreEqual(HttpStatusCode.Created, permissionResponse.StatusCode); Assert.AreEqual(permissionId, permissionResponse.Resource.Id); Assert.AreEqual(Cosmos.PermissionMode.Read, permissionResponse.Resource.PermissionMode); // Valdiate read on contianer masterKeyCredential.Update(permissionResponse.Resource.Token); ToDoActivity item = ToDoActivity.CreateRandomToDoActivity(); Cosmos.Container container = client.GetContainer(databaseName, containerId); responseMessage = await container.ReadContainerStreamAsync(); Assert.AreEqual(HttpStatusCode.OK, responseMessage.StatusCode); responseMessage = await container.CreateItemStreamAsync(TestCommon.SerializerCore.ToStream(item), new Cosmos.PartitionKey(item.id)); Assert.AreEqual(HttpStatusCode.Forbidden, responseMessage.StatusCode); // Read Only resorce token } { // Reset to master key for new permission creation masterKeyCredential.Update(Convert.ToBase64String(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString()))); ToDoActivity item = ToDoActivity.CreateRandomToDoActivity(); Cosmos.Container container = client.GetContainer(databaseName, containerId); responseMessage = await container.CreateItemStreamAsync(TestCommon.SerializerCore.ToStream(item), new Cosmos.PartitionKey(item.id)); Assert.AreEqual(HttpStatusCode.Unauthorized, responseMessage.StatusCode); // Read Only resorce token string diagnostics = responseMessage.Diagnostics.ToString(); Assert.IsTrue(diagnostics.Contains("AuthProvider LifeSpan InSec"), diagnostics.ToString()); } } finally { // Reset to master key for clean-up masterKeyCredential.Update(authKey); await TestCommon.DeleteDatabaseAsync(client, client.GetDatabase(databaseName)); } } }
public async Task ReadReplaceThroughputResponseTests() { int toStreamCount = 0; int fromStreamCount = 0; CosmosSerializerHelper mockJsonSerializer = new CosmosSerializerHelper( null, (x) => fromStreamCount++, (x) => toStreamCount++); //Create a new cosmos client with the mocked cosmos json serializer CosmosClient client = TestCommon.CreateCosmosClient( (cosmosClientBuilder) => cosmosClientBuilder.WithCustomSerializer(mockJsonSerializer)); string databaseId = Guid.NewGuid().ToString(); int throughput = 10000; DatabaseResponse createResponse = await client.CreateDatabaseAsync(databaseId, throughput, null); Assert.AreEqual(HttpStatusCode.Created, createResponse.StatusCode); Cosmos.Database cosmosDatabase = createResponse; ThroughputResponse readThroughputResponse = await cosmosDatabase.ReadThroughputAsync(new RequestOptions()); Assert.IsNotNull(readThroughputResponse); Assert.IsNotNull(readThroughputResponse.Resource); Assert.IsNotNull(readThroughputResponse.MinThroughput); Assert.IsNotNull(readThroughputResponse.Resource.Throughput); Assert.AreEqual(throughput, readThroughputResponse.Resource.Throughput.Value); // Implicit ThroughputProperties throughputProperties = await cosmosDatabase.ReadThroughputAsync(new RequestOptions()); Assert.IsNotNull(throughputProperties); Assert.AreEqual(throughput, throughputProperties.Throughput); // Simple API int?readThroughput = await cosmosDatabase.ReadThroughputAsync(); Assert.AreEqual(throughput, readThroughput); // Database must have a container before it can be scaled string containerId = Guid.NewGuid().ToString(); string partitionPath = "/users"; ContainerResponse containerResponse = await cosmosDatabase.CreateContainerAsync(containerId, partitionPath, throughput : null); Assert.AreEqual(HttpStatusCode.Created, containerResponse.StatusCode); ThroughputResponse replaceThroughputResponse = await cosmosDatabase.ReplaceThroughputAsync(readThroughputResponse.Resource.Throughput.Value + 1000); Assert.IsNotNull(replaceThroughputResponse); Assert.IsNotNull(replaceThroughputResponse.Resource); Assert.AreEqual(readThroughputResponse.Resource.Throughput.Value + 1000, replaceThroughputResponse.Resource.Throughput.Value); await cosmosDatabase.DeleteAsync(); Database databaseNoThroughput = await client.CreateDatabaseAsync(Guid.NewGuid().ToString(), throughput : null); try { ThroughputResponse throughputResponse = await databaseNoThroughput.ReadThroughputAsync(new RequestOptions()); Assert.Fail("Should through not found exception as throughput is not configured"); } catch (CosmosException exception) { Assert.AreEqual(HttpStatusCode.NotFound, exception.StatusCode); } try { ThroughputResponse throughputResponse = await databaseNoThroughput.ReplaceThroughputAsync(2000, new RequestOptions()); Assert.Fail("Should through not found exception as throughput is not configured"); } catch (CosmosException exception) { Assert.AreEqual(HttpStatusCode.NotFound, exception.StatusCode); } int?dbThroughput = await databaseNoThroughput.ReadThroughputAsync(); Assert.IsNull(dbThroughput); Assert.AreEqual(0, toStreamCount, "Custom serializer to stream should not be used for offer operations"); Assert.AreEqual(0, fromStreamCount, "Custom serializer from stream should not be used for offer operations"); await databaseNoThroughput.DeleteAsync(); }
public void VerifySynchronizationContextDoesNotLock() { string databaseId = Guid.NewGuid().ToString(); SynchronizationContext prevContext = SynchronizationContext.Current; try { TestSynchronizationContext syncContext = new TestSynchronizationContext(); SynchronizationContext.SetSynchronizationContext(syncContext); syncContext.Post(_ => { using (CosmosClient client = TestCommon.CreateCosmosClient()) { Cosmos.Database database = client.CreateDatabaseAsync(databaseId).GetAwaiter().GetResult(); database = client.CreateDatabaseIfNotExistsAsync(databaseId).GetAwaiter().GetResult(); database.ReadStreamAsync().ConfigureAwait(false).GetAwaiter().GetResult(); database.ReadAsync().ConfigureAwait(false).GetAwaiter().GetResult(); QueryDefinition databaseQuery = new QueryDefinition("select * from T where T.id = @id").WithParameter("@id", databaseId); FeedIterator <DatabaseProperties> databaseIterator = client.GetDatabaseQueryIterator <DatabaseProperties>(databaseQuery); while (databaseIterator.HasMoreResults) { databaseIterator.ReadNextAsync().GetAwaiter().GetResult(); } Container container = database.CreateContainerAsync(Guid.NewGuid().ToString(), "/pk").GetAwaiter().GetResult(); container = database.CreateContainerIfNotExistsAsync(container.Id, "/pk").GetAwaiter().GetResult(); ToDoActivity testItem = ToDoActivity.CreateRandomToDoActivity(); ItemResponse <ToDoActivity> response = container.CreateItemAsync <ToDoActivity>(item: testItem).ConfigureAwait(false).GetAwaiter().GetResult(); Assert.IsNotNull(response); string diagnostics = response.Diagnostics.ToString(); Assert.IsTrue(diagnostics.Contains("SynchronizationContext")); using CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); try { ToDoActivity tempItem = ToDoActivity.CreateRandomToDoActivity(); CancellationToken cancellationToken = cancellationTokenSource.Token; cancellationTokenSource.Cancel(); container.CreateItemAsync <ToDoActivity>(item: tempItem, cancellationToken: cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult(); Assert.Fail("Should have thrown a cancellation token"); }catch (CosmosOperationCanceledException oe) { string exception = oe.ToString(); Assert.IsTrue(exception.Contains("SynchronizationContext")); } // Test read feed container.GetItemLinqQueryable <ToDoActivity>( allowSynchronousQueryExecution: true, requestOptions: new QueryRequestOptions() { }).ToList(); FeedIterator feedIterator = container.GetItemLinqQueryable <ToDoActivity>() .ToStreamIterator(); while (feedIterator.HasMoreResults) { feedIterator.ReadNextAsync().GetAwaiter().GetResult(); } FeedIterator <ToDoActivity> feedIteratorTyped = container.GetItemLinqQueryable <ToDoActivity>() .ToFeedIterator <ToDoActivity>(); while (feedIteratorTyped.HasMoreResults) { feedIteratorTyped.ReadNextAsync().GetAwaiter().GetResult(); } // Test query container.GetItemLinqQueryable <ToDoActivity>( allowSynchronousQueryExecution: true, requestOptions: new QueryRequestOptions() { }).Where(item => item.id != "").ToList(); FeedIterator queryIterator = container.GetItemLinqQueryable <ToDoActivity>() .Where(item => item.id != "").ToStreamIterator(); while (queryIterator.HasMoreResults) { queryIterator.ReadNextAsync().GetAwaiter().GetResult(); } FeedIterator <ToDoActivity> queryIteratorTyped = container.GetItemLinqQueryable <ToDoActivity>() .Where(item => item.id != "").ToFeedIterator <ToDoActivity>(); while (queryIteratorTyped.HasMoreResults) { queryIteratorTyped.ReadNextAsync().GetAwaiter().GetResult(); } double costAsync = container.GetItemLinqQueryable <ToDoActivity>() .Select(x => x.cost).SumAsync().GetAwaiter().GetResult(); double cost = container.GetItemLinqQueryable <ToDoActivity>( allowSynchronousQueryExecution: true).Select(x => x.cost).Sum(); ItemResponse <ToDoActivity> deleteResponse = container.DeleteItemAsync <ToDoActivity>(partitionKey: new Cosmos.PartitionKey(testItem.pk), id: testItem.id).ConfigureAwait(false).GetAwaiter().GetResult(); Assert.IsNotNull(deleteResponse); } }, state: null); } finally { SynchronizationContext.SetSynchronizationContext(prevContext); using (CosmosClient client = TestCommon.CreateCosmosClient()) { client.GetDatabase(databaseId).DeleteAsync().GetAwaiter().GetResult(); } } }
public static Func <bool, IQueryable <Family> > GenerateFamilyCosmosData( Cosmos.Database cosmosDatabase, out Container container) { // The test collection should have range index on string properties // for the orderby tests PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition { Paths = new System.Collections.ObjectModel.Collection <string>(new[] { "/Pk" }), Kind = PartitionKind.Hash }; var newCol = new ContainerProperties() { Id = Guid.NewGuid().ToString(), PartitionKey = partitionKeyDefinition, IndexingPolicy = new Microsoft.Azure.Cosmos.IndexingPolicy() { IncludedPaths = new Collection <Cosmos.IncludedPath>() { new Cosmos.IncludedPath() { Path = "/*", Indexes = new System.Collections.ObjectModel.Collection <Microsoft.Azure.Cosmos.Index>() { Microsoft.Azure.Cosmos.Index.Range(Microsoft.Azure.Cosmos.DataType.Number, -1), Microsoft.Azure.Cosmos.Index.Range(Microsoft.Azure.Cosmos.DataType.String, -1) } } }, CompositeIndexes = new Collection <Collection <Cosmos.CompositePath> >() { new Collection <Cosmos.CompositePath>() { new Cosmos.CompositePath() { Path = "/FamilyId", Order = Cosmos.CompositePathSortOrder.Ascending }, new Cosmos.CompositePath() { Path = "/Int", Order = Cosmos.CompositePathSortOrder.Ascending } }, new Collection <Cosmos.CompositePath>() { new Cosmos.CompositePath() { Path = "/FamilyId", Order = Cosmos.CompositePathSortOrder.Ascending }, new Cosmos.CompositePath() { Path = "/Int", Order = Cosmos.CompositePathSortOrder.Descending } }, new Collection <Cosmos.CompositePath>() { new Cosmos.CompositePath() { Path = "/FamilyId", Order = Cosmos.CompositePathSortOrder.Ascending }, new Cosmos.CompositePath() { Path = "/Int", Order = Cosmos.CompositePathSortOrder.Ascending }, new Cosmos.CompositePath() { Path = "/IsRegistered", Order = Cosmos.CompositePathSortOrder.Descending } }, new Collection <Cosmos.CompositePath>() { new Cosmos.CompositePath() { Path = "/Int", Order = Cosmos.CompositePathSortOrder.Ascending }, new Cosmos.CompositePath() { Path = "/IsRegistered", Order = Cosmos.CompositePathSortOrder.Descending } }, new Collection <Cosmos.CompositePath>() { new Cosmos.CompositePath() { Path = "/IsRegistered", Order = Cosmos.CompositePathSortOrder.Ascending }, new Cosmos.CompositePath() { Path = "/Int", Order = Cosmos.CompositePathSortOrder.Descending } } } } }; container = cosmosDatabase.CreateContainerAsync(newCol).Result; const int Records = 100; const int MaxNameLength = 100; const int MaxThingStringLength = 50; const int MaxChild = 5; const int MaxPets = MaxChild; const int MaxThings = MaxChild; const int MaxGrade = 101; const int MaxTransaction = 20; const int MaxTransactionMinuteRange = 200; int MaxTransactionType = Enum.GetValues(typeof(TransactionType)).Length; Family createDataObj(Random random) { var obj = new Family { FamilyId = random.NextDouble() < 0.05 ? "some id" : Guid.NewGuid().ToString(), IsRegistered = random.NextDouble() < 0.5, NullableInt = random.NextDouble() < 0.5 ? (int?)random.Next() : null, Int = random.NextDouble() < 0.5 ? 5 : random.Next(), Id = Guid.NewGuid().ToString(), Pk = "Test", Parents = new Parent[random.Next(2) + 1] }; for (int i = 0; i < obj.Parents.Length; ++i) { obj.Parents[i] = new Parent() { FamilyName = LinqTestsCommon.RandomString(random, random.Next(MaxNameLength)), GivenName = LinqTestsCommon.RandomString(random, random.Next(MaxNameLength)) }; } obj.Tags = new string[random.Next(MaxChild)]; for (int i = 0; i < obj.Tags.Length; ++i) { obj.Tags[i] = (i + random.Next(30, 36)).ToString(); } obj.Children = new Child[random.Next(MaxChild)]; for (int i = 0; i < obj.Children.Length; ++i) { obj.Children[i] = new Child() { Gender = random.NextDouble() < 0.5 ? "male" : "female", FamilyName = obj.Parents[random.Next(obj.Parents.Length)].FamilyName, GivenName = LinqTestsCommon.RandomString(random, random.Next(MaxNameLength)), Grade = random.Next(MaxGrade) }; obj.Children[i].Pets = new List <Pet>(); for (int j = 0; j < random.Next(MaxPets); ++j) { obj.Children[i].Pets.Add(new Pet() { GivenName = random.NextDouble() < 0.5 ? LinqTestsCommon.RandomString(random, random.Next(MaxNameLength)) : "Fluffy" }); } obj.Children[i].Things = new Dictionary <string, string>(); for (int j = 0; j < random.Next(MaxThings) + 1; ++j) { obj.Children[i].Things.Add( j == 0 ? "A" : $"{j}-{random.Next().ToString()}", LinqTestsCommon.RandomString(random, random.Next(MaxThingStringLength))); } } obj.Records = new Logs { LogId = LinqTestsCommon.RandomString(random, random.Next(MaxNameLength)), Transactions = new Transaction[random.Next(MaxTransaction)] }; for (int i = 0; i < obj.Records.Transactions.Length; ++i) { var transaction = new Transaction() { Amount = random.Next(), Date = DateTime.Now.AddMinutes(random.Next(MaxTransactionMinuteRange)), Type = (TransactionType)(random.Next(MaxTransactionType)) }; obj.Records.Transactions[i] = transaction; } return(obj); } Func <bool, IQueryable <Family> > getQuery = LinqTestsCommon.GenerateTestCosmosData(createDataObj, Records, container); return(getQuery); }
public async Task InvalidSessionTokenAfterContainerRecreationAndCollectionCacheRefreshReproTest() { // ingestionClinet is dedicated client simulating the writes / container recreation in // the separate process - like Spark job using CosmosClient ingestionClient = TestCommon.CreateCosmosClient(); Cosmos.Database ingestionDatabase = ingestionClient.GetDatabase(this.database.Id); ContainerProperties multiPartitionContainerSettings = new ContainerProperties(id: Guid.NewGuid().ToString(), partitionKeyPath: "/pk"); Container ingestionContainer = await ingestionDatabase.CreateContainerAsync(multiPartitionContainerSettings); const int itemCountToBeIngested = 10; string pk = Guid.NewGuid().ToString("N"); long? latestLsn = null; Console.WriteLine("INGEST DOCUMENTS"); for (int i = 0; i < itemCountToBeIngested; i++) { ToDoActivity testItem = ToDoActivity.CreateRandomToDoActivity(); testItem.pk = pk; ItemResponse <ToDoActivity> response = await ingestionContainer.CreateItemAsync <ToDoActivity>(item : testItem); Assert.IsNotNull(response); Assert.IsNotNull(response.Resource); Assert.IsNotNull(response.Diagnostics); long?lsnAfterCreate = await GetLSNFromSessionContainer( ingestionContainer, multiPartitionContainerSettings, new PartitionKey(pk)); Assert.IsNotNull(lsnAfterCreate); Assert.IsTrue(latestLsn == null || lsnAfterCreate.Value > latestLsn.Value); latestLsn = lsnAfterCreate; CosmosTraceDiagnostics diagnostics = (CosmosTraceDiagnostics)response.Diagnostics; Assert.IsFalse(diagnostics.IsGoneExceptionHit()); Assert.IsFalse(string.IsNullOrEmpty(diagnostics.ToString())); Assert.IsTrue(diagnostics.GetClientElapsedTime() > TimeSpan.Zero); } // Dedciated query client used only for queries simulating the customer's app string lastRequestedSessionToken = null; Container queryContainer = TransportClientHelper.GetContainerWithIntercepter( this.database.Id, ingestionContainer.Id, (uri, operation, request) => { if (request.ResourceType == ResourceType.Document && request.OperationType == OperationType.Query) { lastRequestedSessionToken = request.Headers[HttpConstants.HttpHeaders.SessionToken]; } }, false, null); long?lsnAfterQueryOnOldContainer = null; // Issueing two queries - first won't use session tokens yet // second will provide session tokens captured from first request in the request to the backend for (int i = 0; i < 2; i++) { Console.WriteLine("RUN QUERY ON OLD CONTAINER ({0})", i); using FeedIterator <JObject> queryIteratorOldContainer = queryContainer.GetItemQueryIterator <JObject>( new QueryDefinition("Select c.id FROM c"), continuationToken: null, new QueryRequestOptions { ConsistencyLevel = Cosmos.ConsistencyLevel.Session, PartitionKey = new Cosmos.PartitionKey(pk) }); int itemCountOldContainer = 0; while (queryIteratorOldContainer.HasMoreResults) { FeedResponse <JObject> response = await queryIteratorOldContainer.ReadNextAsync(); if (i == 0) { string diagnosticString = response.Diagnostics.ToString(); Assert.IsTrue(diagnosticString.Contains("PKRangeCache Info(")); JObject diagnosticJobject = JObject.Parse(diagnosticString); JToken actualToken = diagnosticJobject.SelectToken("$.children[0].children[?(@.name=='Get Partition Key Ranges')].children[?(@.name=='Try Get Overlapping Ranges')].data"); JToken actualNode = actualToken.Children().First().First(); Assert.IsTrue(actualNode["Previous Continuation Token"].ToString().Length == 0); Assert.IsTrue(actualNode["Continuation Token"].ToString().Length > 0); } itemCountOldContainer += response.Count; } Assert.AreEqual(itemCountToBeIngested, itemCountOldContainer); lsnAfterQueryOnOldContainer = await GetLSNFromSessionContainer( queryContainer, multiPartitionContainerSettings, new PartitionKey(pk)); Assert.IsNotNull(lsnAfterQueryOnOldContainer); Assert.AreEqual(latestLsn.Value, lsnAfterQueryOnOldContainer.Value); if (i == 0) { Assert.IsNull(lastRequestedSessionToken); } else { Assert.IsNotNull(lastRequestedSessionToken); Assert.AreEqual(latestLsn.Value, SessionTokenHelper.Parse(lastRequestedSessionToken).LSN); } } Console.WriteLine( "DELETE CONTAINER {0}", (await queryContainer.ReadContainerAsync()).Resource.ResourceId); await ingestionContainer.DeleteContainerAsync(); Console.WriteLine("RECREATING CONTAINER..."); ContainerResponse ingestionContainerResponse = await ingestionDatabase.CreateContainerAsync(multiPartitionContainerSettings); ingestionContainer = ingestionContainerResponse.Container; string responseSessionTokenValue = ingestionContainerResponse.Headers[HttpConstants.HttpHeaders.SessionToken]; long?lsnAfterRecreatingContainerFromIngestionClient = responseSessionTokenValue != null? SessionTokenHelper.Parse(responseSessionTokenValue).LSN : null; Console.WriteLine( "RECREATED CONTAINER with new CollectionRid: {0} - LSN: {1}", ingestionContainerResponse.Resource.ResourceId, lsnAfterRecreatingContainerFromIngestionClient); // validates that the query container still uses the LSN captured from the old LSN long?lsnAfterCreatingNewContainerFromQueryClient = await GetLSNFromSessionContainer( queryContainer, multiPartitionContainerSettings, new PartitionKey(pk)); Assert.IsNotNull(lsnAfterCreatingNewContainerFromQueryClient); Assert.AreEqual(latestLsn.Value, lsnAfterCreatingNewContainerFromQueryClient.Value); Console.WriteLine("GET FEED RANGES"); // this will force a CollectionCache refresh - because no pk ranegs can be identified // for the old container anymore _ = await queryContainer.GetFeedRangesAsync(); Console.WriteLine("RUN QUERY ON NEW CONTAINER"); int itemCountNewContainer = 0; using FeedIterator <JObject> queryIteratorNewContainer = queryContainer.GetItemQueryIterator <JObject>( new QueryDefinition("Select c.id FROM c"), continuationToken: null, new QueryRequestOptions { ConsistencyLevel = Cosmos.ConsistencyLevel.Session, PartitionKey = new Cosmos.PartitionKey(pk), }); Console.WriteLine("Query iterator created"); while (queryIteratorNewContainer.HasMoreResults) { Console.WriteLine("Retrieving first page"); try { FeedResponse <JObject> response = await queryIteratorNewContainer.ReadNextAsync(); Console.WriteLine("Request Diagnostics for query against new container: {0}", response.Diagnostics.ToString()); itemCountNewContainer += response.Count; } catch (CosmosException cosmosException) { Console.WriteLine("COSMOS EXCEPTION: {0}", cosmosException); throw; } } Assert.AreEqual(0, itemCountNewContainer); long?lsnAfterQueryOnNewContainer = await GetLSNFromSessionContainer( queryContainer, multiPartitionContainerSettings, new PartitionKey(pk)); Assert.IsNotNull(lsnAfterQueryOnNewContainer); Assert.IsTrue( lastRequestedSessionToken == null || SessionTokenHelper.Parse(lastRequestedSessionToken).LSN == lsnAfterRecreatingContainerFromIngestionClient, $"The requested session token {lastRequestedSessionToken} on the last query request should be null " + $"or have LSN '{lsnAfterRecreatingContainerFromIngestionClient}' (which is the LSN after " + "re-creating the container) if the session cache or the new CollectionName to Rid mapping was " + "correctly populated in the SessionCache."); }
private async Task ValidateCollectionIndexProgressHeaders(CosmosClient client) { Cosmos.Database db = await client.CreateDatabaseAsync(Guid.NewGuid().ToString()); try { PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition { Paths = new System.Collections.ObjectModel.Collection <string>(new[] { "/id" }), Kind = PartitionKind.Hash }; var lazyCollection = new ContainerProperties() { Id = Guid.NewGuid().ToString(), PartitionKey = partitionKeyDefinition }; lazyCollection.IndexingPolicy.IndexingMode = Cosmos.IndexingMode.Lazy; Container lazyContainer = await db.CreateContainerAsync(lazyCollection); var consistentCollection = new ContainerProperties() { Id = Guid.NewGuid().ToString(), PartitionKey = partitionKeyDefinition }; consistentCollection.IndexingPolicy.IndexingMode = Cosmos.IndexingMode.Consistent; Container consistentContainer = await db.CreateContainerAsync(consistentCollection); var noneIndexCollection = new ContainerProperties() { Id = Guid.NewGuid().ToString(), PartitionKey = partitionKeyDefinition }; noneIndexCollection.IndexingPolicy.Automatic = false; noneIndexCollection.IndexingPolicy.IndexingMode = Cosmos.IndexingMode.None; Container noneIndexContainer = await db.CreateContainerAsync(noneIndexCollection); var doc = new Document() { Id = Guid.NewGuid().ToString() }; await lazyContainer.CreateItemAsync <Document>(doc); await consistentContainer.CreateItemAsync <Document>(doc); await noneIndexContainer.CreateItemAsync <Document>(doc); // Lazy-indexing collection. { ContainerResponse collectionResponse = await lazyContainer.ReadContainerAsync(requestOptions : new ContainerRequestOptions { PopulateQuotaInfo = true }); Assert.IsTrue(int.Parse(collectionResponse.Headers[HttpConstants.HttpHeaders.CollectionLazyIndexingProgress], CultureInfo.InvariantCulture) >= 0, "Expect lazy indexer progress when reading lazy collection."); Assert.AreEqual(100, int.Parse(collectionResponse.Headers[HttpConstants.HttpHeaders.CollectionIndexTransformationProgress], CultureInfo.InvariantCulture), "Expect reindexer progress when reading lazy collection."); } // Consistent-indexing collection. { ContainerResponse collectionResponse = await consistentContainer.ReadContainerAsync(requestOptions : new ContainerRequestOptions { PopulateQuotaInfo = true }); Assert.IsFalse(collectionResponse.Headers.AllKeys().Contains(HttpConstants.HttpHeaders.CollectionLazyIndexingProgress), "No lazy indexer progress when reading consistent collection."); Assert.AreEqual(100, int.Parse(collectionResponse.Headers[HttpConstants.HttpHeaders.CollectionIndexTransformationProgress], CultureInfo.InvariantCulture), "Expect reindexer progress when reading consistent collection."); } // None-indexing collection. { ContainerResponse collectionResponse = await noneIndexContainer.ReadContainerAsync(requestOptions : new ContainerRequestOptions { PopulateQuotaInfo = true }); Assert.IsFalse(collectionResponse.Headers.AllKeys().Contains(HttpConstants.HttpHeaders.CollectionLazyIndexingProgress), "No lazy indexer progress when reading none-index collection."); Assert.AreEqual(100, int.Parse(collectionResponse.Headers[HttpConstants.HttpHeaders.CollectionIndexTransformationProgress], CultureInfo.InvariantCulture), "Expect reindexer progress when reading none-index collection."); } } finally { await db.DeleteAsync(); } }