public static Uri SetupSingleRegionAccount( string accountName, Cosmos.ConsistencyLevel consistencyLevel, Mock <IHttpHandler> mockHttpHandler, out string primaryRegionEndpoint) { primaryRegionEndpoint = $"https://{accountName}-eastus.documents.azure.com"; AccountRegion region = new AccountRegion() { Name = "East US", Endpoint = primaryRegionEndpoint }; AccountProperties accountProperties = new AccountProperties() { Id = accountName, WriteLocationsInternal = new Collection <AccountRegion>() { region }, ReadLocationsInternal = new Collection <AccountRegion>() { region }, EnableMultipleWriteLocations = false, Consistency = new AccountConsistency() { DefaultConsistencyLevel = consistencyLevel }, SystemReplicationPolicy = new ReplicationPolicy() { MinReplicaSetSize = 3, MaxReplicaSetSize = 4 }, ReadPolicy = new ReadPolicy() { PrimaryReadCoefficient = 1, SecondaryReadCoefficient = 1 }, ReplicationPolicy = new ReplicationPolicy() { AsyncReplication = false, MinReplicaSetSize = 3, MaxReplicaSetSize = 4 } }; Uri endpointUri = new Uri($"https://{accountName}.documents.azure.com"); mockHttpHandler.Setup(x => x.SendAsync( It.Is <HttpRequestMessage>(x => x.RequestUri == endpointUri), It.IsAny <CancellationToken>())) .Returns <HttpRequestMessage, CancellationToken>((request, cancellationToken) => Task.FromResult(new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = new StringContent(JsonConvert.SerializeObject(accountProperties)) })); return(endpointUri); }
public async Task ConsistencyLevelClientAndRequestOption() { Cosmos.ConsistencyLevel requestOptionLevel = Cosmos.ConsistencyLevel.BoundedStaleness; using CosmosClient client = MockCosmosUtil.CreateMockCosmosClient( accountConsistencyLevel: Cosmos.ConsistencyLevel.Strong, customizeClientBuilder: builder => builder.WithConsistencyLevel(Cosmos.ConsistencyLevel.Eventual)); TestHandler testHandler = new TestHandler((request, cancellationToken) => { Assert.AreEqual(requestOptionLevel.ToString(), request.Headers[HttpConstants.HttpHeaders.ConsistencyLevel]); return TestHandler.ReturnSuccess(); }); RequestInvokerHandler invoker = new RequestInvokerHandler(client, requestedClientConsistencyLevel: null) { InnerHandler = testHandler }; RequestMessage requestMessage = new RequestMessage(HttpMethod.Get, new System.Uri("https://dummy.documents.azure.com:443/dbs")) { ResourceType = ResourceType.Document }; requestMessage.Headers.Add(HttpConstants.HttpHeaders.PartitionKey, "[]"); requestMessage.OperationType = OperationType.Read; requestMessage.RequestOptions = new ItemRequestOptions() { ConsistencyLevel = requestOptionLevel }; await invoker.SendAsync(requestMessage, new CancellationToken()); }
public override async Task <ResponseMessage> SendAsync( RequestMessage request, CancellationToken cancellationToken) { if (request == null) { throw new ArgumentNullException(nameof(request)); } RequestOptions promotedRequestOptions = request.RequestOptions; if (promotedRequestOptions != null) { // Fill request options promotedRequestOptions.PopulateRequestOptions(request); // Validate the request consistency compatibility with account consistency // Type based access context for requested consistency preferred for performance Cosmos.ConsistencyLevel?consistencyLevel = null; if (promotedRequestOptions is ItemRequestOptions) { consistencyLevel = (promotedRequestOptions as ItemRequestOptions).ConsistencyLevel; } else if (promotedRequestOptions is QueryRequestOptions) { consistencyLevel = (promotedRequestOptions as QueryRequestOptions).ConsistencyLevel; } else if (promotedRequestOptions is StoredProcedureRequestOptions) { consistencyLevel = (promotedRequestOptions as StoredProcedureRequestOptions).ConsistencyLevel; } if (consistencyLevel.HasValue) { Cosmos.ConsistencyLevel accountConsistency = await this.client.GetAccountConsistencyLevelAsync(); if (!ValidationHelpers.ValidateConsistencyLevel(accountConsistency, consistencyLevel.Value)) { throw new ArgumentException(string.Format( CultureInfo.CurrentUICulture, RMResources.InvalidConsistencyLevel, consistencyLevel.Value.ToString(), accountConsistency)); } } } await this.client.DocumentClient.EnsureValidClientAsync(); await request.AssertPartitioningDetailsAsync(this.client, cancellationToken); this.FillMultiMasterContext(request); return(await base.SendAsync(request, cancellationToken)); }
/// <summary> /// If isLocalQuorumConsistency flag is true, it allows only "Quorum Read with Eventual Consistency Account". /// It goes through a validation where it doesn't allow strong consistency over weaker consistency. /// </summary> /// <param name="backendConsistency"> Account Level Consistency </param> /// <param name="desiredConsistency"> Request/Client Level Consistency</param> /// <param name="isLocalQuorumConsistency"> Allows Quorum Read with Eventual Account</param> /// <param name="operationType"> <see cref="OperationType"/> </param> /// <param name="resourceType"> <see cref="ResourceType"/> </param> /// <returns>true/false</returns> /// <exception cref="ArgumentException">Invalid Backend Consistency</exception> public static bool IsValidConsistencyLevelOverwrite( Cosmos.ConsistencyLevel backendConsistency, Cosmos.ConsistencyLevel desiredConsistency, bool isLocalQuorumConsistency, OperationType operationType, ResourceType resourceType) { return(ValidationHelpers.IsValidConsistencyLevelOverwrite( backendConsistency: (Documents.ConsistencyLevel)backendConsistency, desiredConsistency: (Documents.ConsistencyLevel)desiredConsistency, isLocalQuorumConsistency: isLocalQuorumConsistency, operationType: operationType, resourceType: resourceType)); }
public void VerifyCosmosConfigurationPropertiesGetUpdated() { string endpoint = AccountEndpoint; string key = MockCosmosUtil.RandomInvalidCorrectlyFormatedAuthKey; string region = Regions.WestCentralUS; ConnectionMode connectionMode = ConnectionMode.Gateway; TimeSpan requestTimeout = TimeSpan.FromDays(1); int maxConnections = 9001; string userAgentSuffix = "testSuffix"; RequestHandler preProcessHandler = new TestHandler(); ApiType apiType = ApiType.Sql; int maxRetryAttemptsOnThrottledRequests = 9999; TimeSpan maxRetryWaitTime = TimeSpan.FromHours(6); bool enableTcpConnectionEndpointRediscovery = true; CosmosSerializationOptions cosmosSerializerOptions = new CosmosSerializationOptions() { IgnoreNullValues = true, PropertyNamingPolicy = CosmosPropertyNamingPolicy.CamelCase, }; TimeSpan idleTcpConnectionTimeout = new TimeSpan(0, 10, 0); TimeSpan openTcpConnectionTimeout = new TimeSpan(0, 0, 5); int maxRequestsPerTcpConnection = 30; int maxTcpConnectionsPerEndpoint = 65535; Cosmos.PortReuseMode portReuseMode = Cosmos.PortReuseMode.PrivatePortPool; IWebProxy webProxy = new TestWebProxy(); Cosmos.ConsistencyLevel consistencyLevel = Cosmos.ConsistencyLevel.ConsistentPrefix; CosmosClientBuilder cosmosClientBuilder = new CosmosClientBuilder( accountEndpoint: endpoint, authKeyOrResourceToken: key); CosmosClient cosmosClient = cosmosClientBuilder.Build(new MockDocumentClient()); CosmosClientOptions clientOptions = cosmosClient.ClientOptions; Assert.AreEqual(endpoint, cosmosClient.Endpoint.OriginalString, "AccountEndpoint did not save correctly"); Assert.AreEqual(key, cosmosClient.AccountKey, "AccountKey did not save correctly"); //Verify the default values are different from the new values Assert.AreNotEqual(region, clientOptions.ApplicationRegion); Assert.IsNull(clientOptions.ApplicationPreferredRegions); Assert.AreNotEqual(connectionMode, clientOptions.ConnectionMode); Assert.AreNotEqual(maxConnections, clientOptions.GatewayModeMaxConnectionLimit); Assert.AreNotEqual(requestTimeout, clientOptions.RequestTimeout); Assert.AreNotEqual(userAgentSuffix, clientOptions.ApplicationName); Assert.AreNotEqual(apiType, clientOptions.ApiType); Assert.IsFalse(clientOptions.AllowBulkExecution); Assert.AreEqual(0, clientOptions.CustomHandlers.Count); Assert.IsNull(clientOptions.SerializerOptions); Assert.IsNotNull(clientOptions.Serializer); Assert.IsNull(clientOptions.WebProxy); Assert.IsFalse(clientOptions.LimitToEndpoint); Assert.IsTrue(clientOptions.EnableTcpConnectionEndpointRediscovery); Assert.IsNull(clientOptions.HttpClientFactory); Assert.AreNotEqual(consistencyLevel, clientOptions.ConsistencyLevel); Assert.IsFalse(clientOptions.EnablePartitionLevelFailover); //Verify GetConnectionPolicy returns the correct values for default ConnectionPolicy policy = clientOptions.GetConnectionPolicy(clientId: 0); Assert.AreEqual(ConnectionMode.Direct, policy.ConnectionMode); Assert.AreEqual(Protocol.Tcp, policy.ConnectionProtocol); Assert.AreEqual(clientOptions.GatewayModeMaxConnectionLimit, policy.MaxConnectionLimit); Assert.AreEqual(clientOptions.RequestTimeout, policy.RequestTimeout); Assert.IsNull(policy.IdleTcpConnectionTimeout); Assert.IsNull(policy.OpenTcpConnectionTimeout); Assert.IsNull(policy.MaxRequestsPerTcpConnection); Assert.IsNull(policy.MaxTcpConnectionsPerEndpoint); Assert.IsTrue(policy.EnableEndpointDiscovery); Assert.IsTrue(policy.EnableTcpConnectionEndpointRediscovery); Assert.IsNull(policy.HttpClientFactory); Assert.AreNotEqual(Cosmos.ConsistencyLevel.Session, clientOptions.ConsistencyLevel); Assert.IsFalse(policy.EnablePartitionLevelFailover); cosmosClientBuilder.WithApplicationRegion(region) .WithConnectionModeGateway(maxConnections, webProxy) .WithRequestTimeout(requestTimeout) .WithApplicationName(userAgentSuffix) .AddCustomHandlers(preProcessHandler) .WithApiType(apiType) .WithThrottlingRetryOptions(maxRetryWaitTime, maxRetryAttemptsOnThrottledRequests) .WithBulkExecution(true) .WithSerializerOptions(cosmosSerializerOptions) .WithConsistencyLevel(consistencyLevel) .WithPartitionLevelFailoverEnabled(); cosmosClient = cosmosClientBuilder.Build(new MockDocumentClient()); clientOptions = cosmosClient.ClientOptions; //Verify all the values are updated Assert.AreEqual(region, clientOptions.ApplicationRegion); Assert.IsNull(clientOptions.ApplicationPreferredRegions); Assert.AreEqual(connectionMode, clientOptions.ConnectionMode); Assert.AreEqual(maxConnections, clientOptions.GatewayModeMaxConnectionLimit); Assert.AreEqual(requestTimeout, clientOptions.RequestTimeout); Assert.AreEqual(userAgentSuffix, clientOptions.ApplicationName); Assert.AreEqual(preProcessHandler, clientOptions.CustomHandlers[0]); Assert.AreEqual(apiType, clientOptions.ApiType); Assert.AreEqual(maxRetryAttemptsOnThrottledRequests, clientOptions.MaxRetryAttemptsOnRateLimitedRequests); Assert.AreEqual(maxRetryWaitTime, clientOptions.MaxRetryWaitTimeOnRateLimitedRequests); Assert.AreEqual(cosmosSerializerOptions.IgnoreNullValues, clientOptions.SerializerOptions.IgnoreNullValues); Assert.AreEqual(cosmosSerializerOptions.PropertyNamingPolicy, clientOptions.SerializerOptions.PropertyNamingPolicy); Assert.AreEqual(cosmosSerializerOptions.Indented, clientOptions.SerializerOptions.Indented); Assert.IsTrue(object.ReferenceEquals(webProxy, clientOptions.WebProxy)); Assert.IsTrue(clientOptions.AllowBulkExecution); Assert.AreEqual(consistencyLevel, clientOptions.ConsistencyLevel); Assert.IsTrue(clientOptions.EnablePartitionLevelFailover); //Verify GetConnectionPolicy returns the correct values policy = clientOptions.GetConnectionPolicy(clientId: 0); Assert.AreEqual(region, policy.PreferredLocations[0]); Assert.AreEqual(ConnectionMode.Gateway, policy.ConnectionMode); Assert.AreEqual(Protocol.Https, policy.ConnectionProtocol); Assert.AreEqual(maxConnections, policy.MaxConnectionLimit); Assert.AreEqual(requestTimeout, policy.RequestTimeout); Assert.IsTrue(policy.UserAgentSuffix.Contains(userAgentSuffix)); Assert.IsTrue(policy.UseMultipleWriteLocations); Assert.AreEqual(maxRetryAttemptsOnThrottledRequests, policy.RetryOptions.MaxRetryAttemptsOnThrottledRequests); Assert.AreEqual((int)maxRetryWaitTime.TotalSeconds, policy.RetryOptions.MaxRetryWaitTimeInSeconds); Assert.AreEqual((Documents.ConsistencyLevel)consistencyLevel, clientOptions.GetDocumentsConsistencyLevel()); Assert.IsTrue(policy.EnablePartitionLevelFailover); IReadOnlyList <string> preferredLocations = new List <string>() { Regions.AustraliaCentral, Regions.AustraliaCentral2 }; //Verify Direct Mode settings cosmosClientBuilder = new CosmosClientBuilder( accountEndpoint: endpoint, authKeyOrResourceToken: key); cosmosClientBuilder.WithConnectionModeDirect( idleTcpConnectionTimeout, openTcpConnectionTimeout, maxRequestsPerTcpConnection, maxTcpConnectionsPerEndpoint, portReuseMode, enableTcpConnectionEndpointRediscovery) .WithApplicationPreferredRegions(preferredLocations); cosmosClient = cosmosClientBuilder.Build(new MockDocumentClient()); clientOptions = cosmosClient.ClientOptions; //Verify all the values are updated Assert.AreEqual(idleTcpConnectionTimeout, clientOptions.IdleTcpConnectionTimeout); Assert.AreEqual(openTcpConnectionTimeout, clientOptions.OpenTcpConnectionTimeout); Assert.AreEqual(maxRequestsPerTcpConnection, clientOptions.MaxRequestsPerTcpConnection); Assert.AreEqual(maxTcpConnectionsPerEndpoint, clientOptions.MaxTcpConnectionsPerEndpoint); Assert.AreEqual(portReuseMode, clientOptions.PortReuseMode); Assert.IsTrue(clientOptions.EnableTcpConnectionEndpointRediscovery); CollectionAssert.AreEqual(preferredLocations.ToArray(), clientOptions.ApplicationPreferredRegions.ToArray()); //Verify GetConnectionPolicy returns the correct values policy = clientOptions.GetConnectionPolicy(clientId: 0); Assert.AreEqual(idleTcpConnectionTimeout, policy.IdleTcpConnectionTimeout); Assert.AreEqual(openTcpConnectionTimeout, policy.OpenTcpConnectionTimeout); Assert.AreEqual(maxRequestsPerTcpConnection, policy.MaxRequestsPerTcpConnection); Assert.AreEqual(maxTcpConnectionsPerEndpoint, policy.MaxTcpConnectionsPerEndpoint); Assert.AreEqual(portReuseMode, policy.PortReuseMode); Assert.IsTrue(policy.EnableTcpConnectionEndpointRediscovery); CollectionAssert.AreEqual(preferredLocations.ToArray(), policy.PreferredLocations.ToArray()); }
public async Task <INameValueCollection> CreateCommonHeadersAsync(FeedOptions feedOptions) { INameValueCollection requestHeaders = new DictionaryNameValueCollection(); Cosmos.ConsistencyLevel defaultConsistencyLevel = (Cosmos.ConsistencyLevel) await this.Client.GetDefaultConsistencyLevelAsync(); Cosmos.ConsistencyLevel?desiredConsistencyLevel = (Cosmos.ConsistencyLevel?) await this.Client.GetDesiredConsistencyLevelAsync(); if (!string.IsNullOrEmpty(feedOptions.SessionToken) && !ReplicatedResourceClient.IsReadingFromMaster(this.ResourceTypeEnum, OperationType.ReadFeed)) { if (defaultConsistencyLevel == Cosmos.ConsistencyLevel.Session || (desiredConsistencyLevel.HasValue && desiredConsistencyLevel.Value == Cosmos.ConsistencyLevel.Session)) { // Query across partitions is not supported today. Master resources (for e.g., database) // can span across partitions, whereas server resources (viz: collection, document and attachment) // don't span across partitions. Hence, session token returned by one partition should not be used // when quering resources from another partition. // Since master resources can span across partitions, don't send session token to the backend. // As master resources are sync replicated, we should always get consistent query result for master resources, // irrespective of the chosen replica. // For server resources, which don't span partitions, specify the session token // for correct replica to be chosen for servicing the query result. requestHeaders[HttpConstants.HttpHeaders.SessionToken] = feedOptions.SessionToken; } } requestHeaders[HttpConstants.HttpHeaders.Continuation] = feedOptions.RequestContinuationToken; requestHeaders[HttpConstants.HttpHeaders.IsQuery] = bool.TrueString; // Flow the pageSize only when we are not doing client eval if (feedOptions.MaxItemCount.HasValue) { requestHeaders[HttpConstants.HttpHeaders.PageSize] = feedOptions.MaxItemCount.ToString(); } requestHeaders[HttpConstants.HttpHeaders.EnableCrossPartitionQuery] = feedOptions.EnableCrossPartitionQuery.ToString(); if (feedOptions.MaxDegreeOfParallelism != 0) { requestHeaders[HttpConstants.HttpHeaders.ParallelizeCrossPartitionQuery] = bool.TrueString; } if (this.feedOptions.EnableScanInQuery != null) { requestHeaders[HttpConstants.HttpHeaders.EnableScanInQuery] = this.feedOptions.EnableScanInQuery.ToString(); } if (this.feedOptions.EmitVerboseTracesInQuery != null) { requestHeaders[HttpConstants.HttpHeaders.EmitVerboseTracesInQuery] = this.feedOptions.EmitVerboseTracesInQuery.ToString(); } if (this.feedOptions.EnableLowPrecisionOrderBy != null) { requestHeaders[HttpConstants.HttpHeaders.EnableLowPrecisionOrderBy] = this.feedOptions.EnableLowPrecisionOrderBy.ToString(); } if (!string.IsNullOrEmpty(this.feedOptions.FilterBySchemaResourceId)) { requestHeaders[HttpConstants.HttpHeaders.FilterBySchemaResourceId] = this.feedOptions.FilterBySchemaResourceId; } if (this.feedOptions.ResponseContinuationTokenLimitInKb != null) { requestHeaders[HttpConstants.HttpHeaders.ResponseContinuationTokenLimitInKB] = this.feedOptions.ResponseContinuationTokenLimitInKb.ToString(); } if (this.feedOptions.ConsistencyLevel.HasValue) { await this.Client.EnsureValidOverwriteAsync((Documents.ConsistencyLevel) feedOptions.ConsistencyLevel.Value); requestHeaders.Set(HttpConstants.HttpHeaders.ConsistencyLevel, this.feedOptions.ConsistencyLevel.Value.ToString()); } else if (desiredConsistencyLevel.HasValue) { requestHeaders.Set(HttpConstants.HttpHeaders.ConsistencyLevel, desiredConsistencyLevel.Value.ToString()); } if (this.feedOptions.EnumerationDirection.HasValue) { requestHeaders.Set(HttpConstants.HttpHeaders.EnumerationDirection, this.feedOptions.EnumerationDirection.Value.ToString()); } if (this.feedOptions.ReadFeedKeyType.HasValue) { requestHeaders.Set(HttpConstants.HttpHeaders.ReadFeedKeyType, this.feedOptions.ReadFeedKeyType.Value.ToString()); } if (this.feedOptions.StartId != null) { requestHeaders.Set(HttpConstants.HttpHeaders.StartId, this.feedOptions.StartId); } if (this.feedOptions.EndId != null) { requestHeaders.Set(HttpConstants.HttpHeaders.EndId, this.feedOptions.EndId); } if (this.feedOptions.StartEpk != null) { requestHeaders.Set(HttpConstants.HttpHeaders.StartEpk, this.feedOptions.StartEpk); } if (this.feedOptions.EndEpk != null) { requestHeaders.Set(HttpConstants.HttpHeaders.EndEpk, this.feedOptions.EndEpk); } if (this.feedOptions.PopulateQueryMetrics) { requestHeaders[HttpConstants.HttpHeaders.PopulateQueryMetrics] = bool.TrueString; } if (this.feedOptions.ForceQueryScan) { requestHeaders[HttpConstants.HttpHeaders.ForceQueryScan] = bool.TrueString; } if (this.feedOptions.MergeStaticId != null) { requestHeaders.Set(HttpConstants.HttpHeaders.MergeStaticId, this.feedOptions.MergeStaticId); } if (this.feedOptions.CosmosSerializationFormatOptions != null) { requestHeaders[HttpConstants.HttpHeaders.ContentSerializationFormat] = this.feedOptions.CosmosSerializationFormatOptions.ContentSerializationFormat; } else if (this.feedOptions.ContentSerializationFormat.HasValue) { requestHeaders[HttpConstants.HttpHeaders.ContentSerializationFormat] = this.feedOptions.ContentSerializationFormat.Value.ToString(); } return(requestHeaders); }
public MockDocumentClient(Cosmos.ConsistencyLevel accountConsistencyLevel) : base(new Uri("http://localhost"), null) { this.accountConsistencyLevel = accountConsistencyLevel; this.Init(); }
/// <summary> /// This can be used to weaken the database account consistency level for read operations. /// If this is not set the database account consistency level will be used for all requests. /// </summary> /// <param name="consistencyLevel">The desired consistency level for the client.</param> /// <returns>The current <see cref="CosmosClientBuilder"/>.</returns> public CosmosClientBuilder WithConsistencyLevel(Cosmos.ConsistencyLevel consistencyLevel) { this.clientOptions.ConsistencyLevel = consistencyLevel; return(this); }
public static bool ValidateConsistencyLevel(Cosmos.ConsistencyLevel backendConsistency, Cosmos.ConsistencyLevel desiredConsistency) { return(ValidationHelpers.ValidateConsistencyLevel((Documents.ConsistencyLevel)backendConsistency, (Documents.ConsistencyLevel)desiredConsistency)); }
public static bool IsValidConsistencyLevelOverwrite(Cosmos.ConsistencyLevel backendConsistency, Cosmos.ConsistencyLevel desiredConsistency) { return(ValidationHelpers.IsValidConsistencyLevelOverwrite((Documents.ConsistencyLevel)backendConsistency, (Documents.ConsistencyLevel)desiredConsistency)); }