diff --git a/Microsoft.Azure.Cosmos/src/ConnectionPolicy.cs b/Microsoft.Azure.Cosmos/src/ConnectionPolicy.cs index cd582f0c18..f77d95b856 100644 --- a/Microsoft.Azure.Cosmos/src/ConnectionPolicy.cs +++ b/Microsoft.Azure.Cosmos/src/ConnectionPolicy.cs @@ -50,7 +50,7 @@ public ConnectionPolicy() this.RetryOptions = new RetryOptions(); this.EnableReadRequestsFallback = null; this.ServerCertificateCustomValidationCallback = null; - + this.AvailabilityStrategy = null; this.CosmosClientTelemetryOptions = new CosmosClientTelemetryOptions(); } @@ -512,6 +512,34 @@ public bool? EnableAdvancedReplicaSelectionForTcp set; } + /// + /// Availability Strategy to be used for periods of high latency + /// + /// /// + /// An example on how to set an availability strategy custom serializer. + /// + /// { "East US", "Central US", "West US" } ) + /// .WithAvailabilityStrategy( + /// AvailabilityStrategy.CrossRegionHedgingStrategy( + /// threshold: TimeSpan.FromMilliseconds(500), + /// thresholdStep: TimeSpan.FromMilliseconds(100) + /// )) + /// .Build(); + /// ]]> + /// + /// + /// + /// The availability strategy in the example is a Cross Region Hedging Strategy. + /// These strategies take two values, a threshold and a threshold step.When a request that is sent + /// out takes longer than the threshold time, the SDK will hedge to the second region in the application preferred regions list. + /// If a response from either the primary request or the first hedged request is not received + /// after the threshold step time, the SDK will hedge to the third region and so on. + /// + public AvailabilityStrategy AvailabilityStrategy { get; set; } + /// /// (Direct/TCP) This is an advanced setting that controls the number of TCP connections that will be opened eagerly to each Cosmos DB back-end. /// @@ -545,6 +573,15 @@ internal SessionRetryOptions SessionRetryOptions set; } + /// + /// A string containing the application name. + /// + internal string ApplicationName + { + get; + set; + } + /// /// GlobalEndpointManager will subscribe to this event if user updates the preferredLocations list in the Azure Cosmos DB service. /// diff --git a/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs b/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs index ac785c8068..3f60995b4a 100644 --- a/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs +++ b/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs @@ -54,13 +54,7 @@ public class CosmosClientOptions private const string ConnectionStringAccountKey = "AccountKey"; private const string ConnectionStringDisableServerCertificateValidation = "DisableServerCertificateValidation"; - private const ApiType DefaultApiType = ApiType.None; - - /// - /// Default thresholds for PPAF request hedging. - /// - private const int DefaultHedgingThresholdInMilliseconds = 1000; - private const int DefaultHedgingThresholdStepInMilliseconds = 500; + private const ApiType DefaultApiType = ApiType.None; /// /// Default request timeout @@ -771,15 +765,6 @@ bool EnableRemoteRegionPreferredForSessionRetry set => this.SessionRetryOptions.RemoteRegionPreferred = value; } - /// - /// Gets or sets a value indicating whether partition-level failover is enabled. When this feature is enabled, - /// the SDK by default applies a cross-region hedging strategy with a default threshold of 1 seconds. - /// If an availability strategy is provided explicitly, then it will be honored, and the default policy wouldn't be applied. Note that - /// the default availability strategy can be opted out by setting as the availability strategy in - /// cosmos client options. - /// - internal bool EnablePartitionLevelFailover { get; set; } = ConfigurationManager.IsPartitionLevelFailoverEnabled(defaultValue: false); - /// /// Enable partition level circuit breaker (aka PPCB). For compute gateway use case, by default per partition automatic failover will be disabled, so does the PPCB. /// If compute gateway chooses to enable PPAF, then the .NET SDK will enable PPCB by default, which will improve the read availability and latency. This would mean @@ -1028,10 +1013,10 @@ internal virtual ConnectionPolicy GetConnectionPolicy(int clientId) { this.ValidateDirectTCPSettings(); this.ValidateLimitToEndpointSettings(); - this.InitializePartitionLevelFailoverWithDefaultHedging(); ConnectionPolicy connectionPolicy = new ConnectionPolicy() - { + { + ApplicationName = this.ApplicationName, MaxConnectionLimit = this.GatewayModeMaxConnectionLimit, RequestTimeout = this.RequestTimeout, ConnectionMode = this.ConnectionMode, @@ -1044,14 +1029,14 @@ internal virtual ConnectionPolicy GetConnectionPolicy(int clientId) MaxRequestsPerTcpConnection = this.MaxRequestsPerTcpConnection, MaxTcpConnectionsPerEndpoint = this.MaxTcpConnectionsPerEndpoint, EnableEndpointDiscovery = !this.LimitToEndpoint, - EnablePartitionLevelFailover = this.EnablePartitionLevelFailover, - EnablePartitionLevelCircuitBreaker = this.EnablePartitionLevelFailover || this.EnablePartitionLevelCircuitBreaker, + EnablePartitionLevelCircuitBreaker = this.EnablePartitionLevelCircuitBreaker, PortReuseMode = this.portReuseMode, EnableTcpConnectionEndpointRediscovery = this.EnableTcpConnectionEndpointRediscovery, EnableAdvancedReplicaSelectionForTcp = this.EnableAdvancedReplicaSelectionForTcp, HttpClientFactory = this.httpClientFactory, ServerCertificateCustomValidationCallback = this.ServerCertificateCustomValidationCallback, - CosmosClientTelemetryOptions = new CosmosClientTelemetryOptions() + CosmosClientTelemetryOptions = new CosmosClientTelemetryOptions(), + AvailabilityStrategy = this.AvailabilityStrategy, }; if (this.CosmosClientTelemetryOptions != null) @@ -1262,47 +1247,9 @@ internal UserAgentContainer CreateUserAgentContainerWithFeatures(int clientId) return new UserAgentContainer( clientId: clientId, features: featureString, - regionConfiguration: regionConfiguration, - suffix: this.GetUserAgentSuffix()); - } - - internal void InitializePartitionLevelFailoverWithDefaultHedging() - { - if (this.EnablePartitionLevelFailover - && this.AvailabilityStrategy == null) - { - // The default threshold is the minimum value of 1 second and a fraction (currently it's half) of - // the request timeout value provided by the end customer. - double defaultThresholdInMillis = Math.Min(CosmosClientOptions.DefaultHedgingThresholdInMilliseconds, this.RequestTimeout.TotalMilliseconds / 2); - - this.AvailabilityStrategy = AvailabilityStrategy.CrossRegionHedgingStrategy( - threshold: TimeSpan.FromMilliseconds(defaultThresholdInMillis), - thresholdStep: TimeSpan.FromMilliseconds(CosmosClientOptions.DefaultHedgingThresholdStepInMilliseconds)); - } + regionConfiguration: regionConfiguration, + suffix: this.ApplicationName); } - - internal string GetUserAgentSuffix() - { - int featureFlag = 0; - if (this.EnablePartitionLevelFailover) - { - featureFlag += (int)UserAgentFeatureFlags.PerPartitionAutomaticFailover; - } - - if (this.EnablePartitionLevelFailover || this.EnablePartitionLevelCircuitBreaker) - { - featureFlag += (int)UserAgentFeatureFlags.PerPartitionCircuitBreaker; - } - - if (featureFlag == 0) - { - return this.ApplicationName; - } - - return string.IsNullOrEmpty(this.ApplicationName) ? - $"F{featureFlag:X}" : - $"F{featureFlag:X}|{this.ApplicationName}"; - } /// /// This generates a key that added to the user agent to make it diff --git a/Microsoft.Azure.Cosmos/src/DocumentClient.cs b/Microsoft.Azure.Cosmos/src/DocumentClient.cs index e51bcf35e9..22a9b55c5a 100644 --- a/Microsoft.Azure.Cosmos/src/DocumentClient.cs +++ b/Microsoft.Azure.Cosmos/src/DocumentClient.cs @@ -112,6 +112,12 @@ internal partial class DocumentClient : IDisposable, IAuthorizationTokenProvider private const int DefaultRntbdSendHangDetectionTimeSeconds = 10; private const bool DefaultEnableCpuMonitor = true; private const string DefaultInitTaskKey = "InitTaskKey"; + + /// + /// Default thresholds for PPAF request hedging. + /// + private const int DefaultHedgingThresholdInMilliseconds = 1000; + private const int DefaultHedgingThresholdStepInMilliseconds = 500; private static readonly char[] resourceIdOrFullNameSeparators = new char[] { '/' }; private static readonly char[] resourceIdSeparators = new char[] { '/', '\\', '?', '#' }; @@ -425,8 +431,8 @@ internal DocumentClient(Uri serviceEndpoint, transportClientHandlerFactory, storeClientFactory) { - } - + } + /// /// Initializes a new instance of the class using the /// specified service endpoint, an authorization key (or resource token) and a connection policy @@ -508,7 +514,7 @@ internal DocumentClient(Uri serviceEndpoint, enableAsyncCacheExceptionNoSharing: this.enableAsyncCacheExceptionNoSharing); this.chaosInterceptorFactory = chaosInterceptorFactory; this.chaosInterceptor = chaosInterceptorFactory?.CreateInterceptor(this); - this.isThinClientEnabled = ConfigurationManager.IsThinClientEnabled(defaultValue: false); + this.isThinClientEnabled = ConfigurationManager.IsThinClientEnabled(defaultValue: false); this.Initialize( serviceEndpoint: serviceEndpoint, @@ -954,15 +960,8 @@ internal virtual void Initialize(Uri serviceEndpoint, ServicePointAccessor servicePoint = ServicePointAccessor.FindServicePoint(this.ServiceEndpoint); servicePoint.ConnectionLimit = this.ConnectionPolicy.MaxConnectionLimit; } -#endif - - this.GlobalEndpointManager = new GlobalEndpointManager(this, this.ConnectionPolicy, this.enableAsyncCacheExceptionNoSharing); - this.PartitionKeyRangeLocation = this.ConnectionPolicy.EnablePartitionLevelFailover || this.ConnectionPolicy.EnablePartitionLevelCircuitBreaker - ? new GlobalPartitionEndpointManagerCore( - this.GlobalEndpointManager, - this.ConnectionPolicy.EnablePartitionLevelFailover, - this.ConnectionPolicy.EnablePartitionLevelCircuitBreaker) - : GlobalPartitionEndpointManagerNoOp.Instance; +#endif + this.GlobalEndpointManager = new GlobalEndpointManager(this, this.ConnectionPolicy, this.enableAsyncCacheExceptionNoSharing); this.httpClient = CosmosHttpClientCore.CreateWithConnectionPolicy( this.ApiType, @@ -1003,13 +1002,6 @@ internal virtual void Initialize(Uri serviceEndpoint, this.sessionContainer = new SessionContainer(this.ServiceEndpoint.Host); } - this.retryPolicy = new RetryPolicy( - globalEndpointManager: this.GlobalEndpointManager, - connectionPolicy: this.ConnectionPolicy, - partitionKeyRangeLocationCache: this.PartitionKeyRangeLocation); - - this.ResetSessionTokenRetryPolicy = this.retryPolicy; - this.desiredConsistencyLevel = desiredConsistencyLevel; // Setup the proxy to be used based on connection mode. // For gateway: GatewayProxy. @@ -1062,7 +1054,34 @@ private async Task GetInitializationTaskAsync(IStoreClientFactory storeCli if (this.desiredConsistencyLevel.HasValue) { this.EnsureValidOverwrite(this.desiredConsistencyLevel.Value); - } + } + + bool isPPafEnabled = ConfigurationManager.IsPartitionLevelFailoverEnabled(defaultValue: false); + if (this.accountServiceConfiguration != null && this.accountServiceConfiguration.AccountProperties.EnablePartitionLevelFailover.HasValue) + { + isPPafEnabled = this.accountServiceConfiguration.AccountProperties.EnablePartitionLevelFailover.Value; + } + + this.ConnectionPolicy.EnablePartitionLevelFailover = isPPafEnabled; + this.ConnectionPolicy.EnablePartitionLevelCircuitBreaker |= this.ConnectionPolicy.EnablePartitionLevelFailover; + this.ConnectionPolicy.UserAgentContainer.AppendFeatures(this.GetUserAgentFeatures()); + this.InitializePartitionLevelFailoverWithDefaultHedging(); + + this.PartitionKeyRangeLocation = + this.ConnectionPolicy.EnablePartitionLevelFailover + || this.ConnectionPolicy.EnablePartitionLevelCircuitBreaker + ? new GlobalPartitionEndpointManagerCore( + this.GlobalEndpointManager, + this.ConnectionPolicy.EnablePartitionLevelFailover, + this.ConnectionPolicy.EnablePartitionLevelCircuitBreaker) + : GlobalPartitionEndpointManagerNoOp.Instance; + + this.retryPolicy = new RetryPolicy( + globalEndpointManager: this.GlobalEndpointManager, + connectionPolicy: this.ConnectionPolicy, + partitionKeyRangeLocationCache: this.PartitionKeyRangeLocation); + + this.ResetSessionTokenRetryPolicy = this.retryPolicy; GatewayStoreModel gatewayStoreModel = new GatewayStoreModel( this.GlobalEndpointManager, @@ -6820,12 +6839,44 @@ private async Task InitializeGatewayConfigurationReaderAsync() this.accountServiceConfiguration = new CosmosAccountServiceConfiguration(accountReader.InitializeReaderAsync); - await this.accountServiceConfiguration.InitializeAsync(); - AccountProperties accountProperties = this.accountServiceConfiguration.AccountProperties; + await this.accountServiceConfiguration.InitializeAsync(); + AccountProperties accountProperties = this.accountServiceConfiguration.AccountProperties; this.UseMultipleWriteLocations = this.ConnectionPolicy.UseMultipleWriteLocations && accountProperties.EnableMultipleWriteLocations; - this.GlobalEndpointManager.InitializeAccountPropertiesAndStartBackgroundRefresh(accountProperties); } + + internal string GetUserAgentFeatures() + { + int featureFlag = 0; + if (this.ConnectionPolicy.EnablePartitionLevelFailover) + { + featureFlag += (int)UserAgentFeatureFlags.PerPartitionAutomaticFailover; + } + + if (this.ConnectionPolicy.EnablePartitionLevelFailover || this.ConnectionPolicy.EnablePartitionLevelCircuitBreaker) + { + featureFlag += (int)UserAgentFeatureFlags.PerPartitionCircuitBreaker; + } + + return featureFlag == 0 ? string.Empty : $"F{featureFlag:X}"; + } + + internal void InitializePartitionLevelFailoverWithDefaultHedging() + { + if (this.ConnectionPolicy.EnablePartitionLevelFailover + && this.ConnectionPolicy.AvailabilityStrategy == null) + { + // The default threshold is the minimum value of 1 second and a fraction (currently it's half) of + // the request timeout value provided by the end customer. + double defaultThresholdInMillis = Math.Min( + DocumentClient.DefaultHedgingThresholdInMilliseconds, + this.ConnectionPolicy.RequestTimeout.TotalMilliseconds / 2); + + this.ConnectionPolicy.AvailabilityStrategy = AvailabilityStrategy.CrossRegionHedgingStrategy( + threshold: TimeSpan.FromMilliseconds(defaultThresholdInMillis), + thresholdStep: TimeSpan.FromMilliseconds(DocumentClient.DefaultHedgingThresholdStepInMilliseconds)); + } + } internal void CaptureSessionToken(DocumentServiceRequest request, DocumentServiceResponse response) { diff --git a/Microsoft.Azure.Cosmos/src/Fluent/CosmosClientBuilder.cs b/Microsoft.Azure.Cosmos/src/Fluent/CosmosClientBuilder.cs index f91ce44a0e..5e7ce3d116 100644 --- a/Microsoft.Azure.Cosmos/src/Fluent/CosmosClientBuilder.cs +++ b/Microsoft.Azure.Cosmos/src/Fluent/CosmosClientBuilder.cs @@ -754,15 +754,6 @@ internal CosmosClientBuilder WithCpuMonitorDisabled() return this; } - /// - /// Enabled partition level failover in the SDK - /// - internal CosmosClientBuilder WithPartitionLevelFailoverEnabled() - { - this.clientOptions.EnablePartitionLevelFailover = true; - return this; - } - /// /// Enables SDK to inject fault. Used for testing applications. /// diff --git a/Microsoft.Azure.Cosmos/src/Handler/RequestInvokerHandler.cs b/Microsoft.Azure.Cosmos/src/Handler/RequestInvokerHandler.cs index 01d37d3378..7499ac178e 100644 --- a/Microsoft.Azure.Cosmos/src/Handler/RequestInvokerHandler.cs +++ b/Microsoft.Azure.Cosmos/src/Handler/RequestInvokerHandler.cs @@ -127,7 +127,7 @@ public override async Task SendAsync( public AvailabilityStrategyInternal AvailabilityStrategy(RequestMessage request) { AvailabilityStrategy strategy = request.RequestOptions?.AvailabilityStrategy - ?? this.client.ClientOptions.AvailabilityStrategy; + ?? this.client.DocumentClient.ConnectionPolicy.AvailabilityStrategy; if (strategy == null) { diff --git a/Microsoft.Azure.Cosmos/src/Resource/Settings/AccountProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Settings/AccountProperties.cs index cfc42707fb..9157964b9e 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Settings/AccountProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Settings/AccountProperties.cs @@ -244,6 +244,12 @@ internal long ProvisionedDocumentStorageInMB [JsonProperty(PropertyName = Constants.Properties.EnableMultipleWriteLocations)] internal bool EnableMultipleWriteLocations { get; set; } + /// + /// Gets the featured enabled value for Per Partition Automatic Failover + /// + [JsonProperty(PropertyName = Constants.Properties.EnablePerPartitionFailoverBehavior)] + internal bool? EnablePartitionLevelFailover { get; set; } + private IDictionary QueryStringToDictConverter() { if (!string.IsNullOrEmpty(this.QueryEngineConfigurationString)) diff --git a/Microsoft.Azure.Cosmos/src/Routing/GlobalEndpointManager.cs b/Microsoft.Azure.Cosmos/src/Routing/GlobalEndpointManager.cs index 3762ced7ea..b9ce687c32 100644 --- a/Microsoft.Azure.Cosmos/src/Routing/GlobalEndpointManager.cs +++ b/Microsoft.Azure.Cosmos/src/Routing/GlobalEndpointManager.cs @@ -597,6 +597,14 @@ public virtual void InitializeAccountPropertiesAndStartBackgroundRefresh(Account { return; } + + bool isPPafEnabled = ConfigurationManager.IsPartitionLevelFailoverEnabled(defaultValue: false); + if (databaseAccount.EnablePartitionLevelFailover.HasValue) + { + isPPafEnabled = databaseAccount.EnablePartitionLevelFailover.Value; + } + + this.connectionPolicy.EnablePartitionLevelFailover = isPPafEnabled; GlobalEndpointManager.ParseThinClientLocationsFromAdditionalProperties(databaseAccount); this.locationCache.OnDatabaseAccountRead(databaseAccount); diff --git a/Microsoft.Azure.Cosmos/src/UserAgentContainer.cs b/Microsoft.Azure.Cosmos/src/UserAgentContainer.cs index d91aa8b3fb..ae9e3d4457 100644 --- a/Microsoft.Azure.Cosmos/src/UserAgentContainer.cs +++ b/Microsoft.Azure.Cosmos/src/UserAgentContainer.cs @@ -29,6 +29,17 @@ public UserAgentContainer( this.Suffix = suffix ?? string.Empty; } + public void AppendFeatures( + string features) + { + if (!string.IsNullOrEmpty(features)) + { + this.Suffix = string.IsNullOrEmpty(this.Suffix) + ? features + : $"{features}|{this.Suffix}"; + } + } + internal override string BaseUserAgent => this.cosmosBaseUserAgent ?? string.Empty; protected virtual void GetEnvironmentInformation( diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemIntegrationTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemIntegrationTests.cs index 45551f0bef..5ee7266408 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemIntegrationTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemIntegrationTests.cs @@ -1312,7 +1312,7 @@ public async Task ReadItemAsync_WithPPAFEnabledAndSingleMasterAccountWithRespons traceDiagnostic.Value.Data.TryGetValue("Hedge Context", out object hedgeContext); - if (cosmosClientOptions.EnablePartitionLevelFailover) + if (enablePartitionLevelFailover) { Assert.IsNotNull(hedgeContext); List hedgedRegions = ((IEnumerable)hedgeContext).ToList(); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CustomSerializationTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CustomSerializationTests.cs index 3334c201d1..96f8d3b0ce 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CustomSerializationTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CustomSerializationTests.cs @@ -14,6 +14,7 @@ namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; + using Microsoft.Azure.Cosmos.Tracing; using Microsoft.Azure.Cosmos.Utils; using Microsoft.Azure.Documents; using Microsoft.Azure.Documents.Client; @@ -244,6 +245,7 @@ public async Task TestStoredProcJsonSerializerSettings() }"; DocumentClient client = new DocumentClient(this.hostUri, this.masterKey, serializerSettings); + await client.EnsureValidClientAsync(NoOpTrace.Singleton); StoredProcedure sproc = await client.CreateStoredProcedureAsync(this.collectionUri, storedProcedureDef); @@ -326,6 +328,8 @@ public void TestStoredProcedure() connectionPolicy, defaultConsistencyLevel); + client.EnsureValidClientAsync(NoOpTrace.Singleton).Wait(); + // Create a simple stored procedure string scriptId = "bulkImportScript"; StoredProcedure sproc = new StoredProcedure @@ -533,6 +537,9 @@ private void SetupDateTimeScenario(JsonSerializerSettings serializerSettings, st serializerSettings, connectionPolicy, defaultConsistencyLevel); + + client.EnsureValidClientAsync(NoOpTrace.Singleton).Wait(); + originalDocument = new Document(); originalDocument.SetPropertyValue(jsonPropertyName, "2017-05-18T17:17:32.7514920Z"); originalDocument.SetPropertyValue(PartitionKeyProperty, "value"); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/DocumentClientUnitTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/DocumentClientUnitTests.cs index 227f308baf..43fe495852 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/DocumentClientUnitTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/DocumentClientUnitTests.cs @@ -13,6 +13,7 @@ namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests using Microsoft.Azure.Cosmos.Internal; using Microsoft.Azure.Cosmos.Linq; using Microsoft.Azure.Cosmos.Query.Core.QueryPlan; + using Microsoft.Azure.Cosmos.Tracing; using Microsoft.Azure.Cosmos.Utils; using Microsoft.Azure.Documents; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -58,6 +59,7 @@ public async Task RetryExceedingMaxTimeLimit() (HttpMessageHandler)null, connectionPolicy); + await client.EnsureValidClientAsync(NoOpTrace.Singleton); await client.GetDatabaseAccountAsync(); int expectedExecutionTimes = 11; @@ -144,6 +146,7 @@ public async Task OpenConnectionsToAllReplicasAsync_WhenStoreModelThrowsInternal (HttpMessageHandler)null, connectionPolicy); + await client.EnsureValidClientAsync(NoOpTrace.Singleton); await client.GetDatabaseAccountAsync(); client.StoreModel = mockStoreModel.Object; client.GatewayStoreModel = mockStoreModel.Object; @@ -200,6 +203,7 @@ private void TestRetryOnThrottled(int? numberOfRetries) (HttpMessageHandler)null, connectionPolicy); + client.EnsureValidClientAsync(NoOpTrace.Singleton).Wait(); client.GetDatabaseAccountAsync().Wait(); int expectedExecutionTimes = numberOfRetries + 1 ?? 10; diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/HeadersValidationTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/HeadersValidationTests.cs index 9120e7179a..047c5b0332 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/HeadersValidationTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/HeadersValidationTests.cs @@ -745,15 +745,14 @@ public async Task ValidateVersionHeader() HttpConstants.Versions.CurrentVersion = "2015-01-01"; client.Dispose(); client = TestCommon.CreateClient(true); - try - { - doc = (await client.CreateDocumentAsync(coll.SelfLink, new Document())).Resource; - Assert.Fail("Should have faild because of version error"); - } - catch (CosmosException dce) - { - Assert.AreEqual(dce.StatusCode, HttpStatusCode.BadRequest); - } + Assert.Fail("Should have faild because of version error"); + } + catch (AggregateException ae) + { + Assert.IsTrue(ae.InnerException is CosmosException); + + CosmosException ce = (CosmosException) ae.InnerException; + Assert.AreEqual(ce.StatusCode, HttpStatusCode.BadRequest); } finally { diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Utils/TestCommon.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Utils/TestCommon.cs index e66f723121..6cc922b35d 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Utils/TestCommon.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Utils/TestCommon.cs @@ -246,6 +246,7 @@ internal static DocumentClient CreateClient(bool useGateway, Protocol protocol = apiType, recievedResponseEventHandler); + client.EnsureValidClientAsync(NoOpTrace.Singleton).Wait(); return client; } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs index 246f6914f8..04a1181921 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs @@ -87,7 +87,7 @@ public void VerifyCosmosConfigurationPropertiesGetUpdated() Assert.IsNull(clientOptions.HttpClientFactory); Assert.AreNotEqual(consistencyLevel, clientOptions.ConsistencyLevel); Assert.AreNotEqual(priorityLevel, clientOptions.PriorityLevel); - Assert.IsFalse(clientOptions.EnablePartitionLevelFailover); + Assert.IsFalse(clientOptions.EnablePartitionLevelCircuitBreaker); Assert.IsFalse(clientOptions.EnableAdvancedReplicaSelectionForTcp.HasValue); Assert.AreNotEqual(throughputBucket, clientOptions.ThroughputBucket); @@ -149,7 +149,7 @@ public void VerifyCosmosConfigurationPropertiesGetUpdated() Assert.IsTrue(clientOptions.AllowBulkExecution); Assert.AreEqual(consistencyLevel, clientOptions.ConsistencyLevel); Assert.AreEqual(priorityLevel, clientOptions.PriorityLevel); - Assert.IsFalse(clientOptions.EnablePartitionLevelFailover); + Assert.IsFalse(clientOptions.EnablePartitionLevelCircuitBreaker); Assert.IsTrue(clientOptions.EnableAdvancedReplicaSelectionForTcp.HasValue && clientOptions.EnableAdvancedReplicaSelectionForTcp.Value); Assert.AreEqual(throughputBucket, clientOptions.ThroughputBucket); @@ -231,17 +231,11 @@ public void VerifyCosmosConfigurationPropertiesGetUpdated() /// [TestMethod] [Owner("dkunda")] - [DataRow(true, DisplayName = "Validate that when environment variable is used to enable PPAF, the outcome of the test should be same.")] - [DataRow(false, DisplayName = "Validate that when CosmosClientOptions is used to enable PPAF, the outcome of the test should be same.")] - public void CosmosClientOptions_WhenPartitionLevelFailoverEnabledAndPreferredRegionsNotSet_ShouldInitializeCosmosClientSuccessfully( - bool useEnvironmentVariable) + public void CosmosClientOptions_WhenPartitionLevelFailoverEnabledAndPreferredRegionsNotSet_ShouldInitializeCosmosClientSuccessfully() { try { - if (useEnvironmentVariable) - { - Environment.SetEnvironmentVariable(ConfigurationManager.PartitionLevelFailoverEnabled, "True"); - } + Environment.SetEnvironmentVariable(ConfigurationManager.PartitionLevelFailoverEnabled, "True"); string endpoint = AccountEndpoint; string key = MockCosmosUtil.RandomInvalidCorrectlyFormatedAuthKey; @@ -277,12 +271,6 @@ public void CosmosClientOptions_WhenPartitionLevelFailoverEnabledAndPreferredReg .WithPriorityLevel(priorityLevel) .WithThroughputBucket(throughputBucket); - if (!useEnvironmentVariable) - { - cosmosClientBuilder - .WithPartitionLevelFailoverEnabled(); - } - CosmosClient cosmosClient = cosmosClientBuilder.Build(); Assert.IsNotNull(cosmosClient, @@ -300,16 +288,11 @@ public void CosmosClientOptions_WhenPartitionLevelFailoverEnabledAndPreferredReg /// [TestMethod] [Owner("dkunda")] - [DataRow(true, DisplayName = "Validate that when enevironment variable is used to enable PPAF, the outcome of the test should be same.")] - [DataRow(false, DisplayName = "Validate that when CosmosClientOptions is used to enable PPAF, the outcome of the test should be same.")] - public void CosmosClientOptions_WhenPartitionLevelFailoverEnabledAndPreferredRegionsSet_ShouldInitializeSuccessfully(bool useEnvironmentVariable) + public void CosmosClientOptions_WhenPartitionLevelFailoverEnabledAndPreferredRegionsSet_ShouldInitializeSuccessfully() { try { - if (useEnvironmentVariable) - { - Environment.SetEnvironmentVariable(ConfigurationManager.PartitionLevelFailoverEnabled, "True"); - } + Environment.SetEnvironmentVariable(ConfigurationManager.PartitionLevelFailoverEnabled, "True"); string endpoint = AccountEndpoint; string key = MockCosmosUtil.RandomInvalidCorrectlyFormatedAuthKey; @@ -342,7 +325,6 @@ public void CosmosClientOptions_WhenPartitionLevelFailoverEnabledAndPreferredReg .WithSerializerOptions(cosmosSerializerOptions) .WithConsistencyLevel(consistencyLevel) .WithPriorityLevel(priorityLevel) - .WithPartitionLevelFailoverEnabled() .WithThroughputBucket(throughputBucket) .WithApplicationPreferredRegions( new List() @@ -373,7 +355,6 @@ public void CosmosClientOptions_WhenPartitionLevelFailoverEnabledAndPreferredReg Assert.AreEqual(cosmosSerializerOptions.Indented, clientOptions.SerializerOptions.Indented); Assert.IsFalse(clientOptions.AllowBulkExecution); Assert.AreEqual(consistencyLevel, clientOptions.ConsistencyLevel); - Assert.IsTrue(clientOptions.EnablePartitionLevelFailover); Assert.IsNotNull(clientOptions.ApplicationPreferredRegions); Assert.IsNotNull(clientOptions.AccountInitializationCustomEndpoints); } @@ -513,69 +494,75 @@ public void UserAgentContainsEnvironmentInformation() [TestMethod] [Owner("ntripician")] - [DataRow(true, new string[] { nameof(UserAgentFeatureFlags.PerPartitionCircuitBreaker) }, "F2", DisplayName = "With PPCB and ApplicationName")] - [DataRow(true, new string[] { nameof(UserAgentFeatureFlags.PerPartitionCircuitBreaker), nameof(UserAgentFeatureFlags.PerPartitionAutomaticFailover) }, "F3", DisplayName = "With PPAF and ApplicationName")] - [DataRow(false, new string[] { nameof(UserAgentFeatureFlags.PerPartitionCircuitBreaker) }, "F2", DisplayName = "With PPCB and Without ApplicationName")] - [DataRow(false, new string[] { }, "", DisplayName = "Without Any Features and ApplicationName")] + [DataRow(true, false, true, "F2", DisplayName = "With PPCB and ApplicationName")] + [DataRow(true, true, true, "F3", DisplayName = "With PPAF and ApplicationName")] + [DataRow(false, false, true, "F2", DisplayName = "With PPCB and Without ApplicationName")] + [DataRow(false, false, false, "", DisplayName = "Without Any Features and ApplicationName")] public void UserAgentContainsPPAFInformation( bool appName, - string[] featureList, + bool ppaf, + bool ppcb, string expectedHexStringPostFix) { EnvironmentInformation environmentInformation = new EnvironmentInformation(); string expectedValue = "cosmos-netstandard-sdk/" + environmentInformation.ClientVersion; - CosmosClientOptions cosmosClientOptions = new CosmosClientOptions(); string userAgentSuffix = "testSuffix"; + + string endpoint = AccountEndpoint; + string key = MockCosmosUtil.RandomInvalidCorrectlyFormatedAuthKey; + + CosmosClientBuilder cosmosClientBuilder = new CosmosClientBuilder( + accountEndpoint: endpoint, + authKeyOrResourceToken: key); + if (appName) { - cosmosClientOptions.ApplicationName = userAgentSuffix; + cosmosClientBuilder.WithApplicationName(userAgentSuffix); } - foreach(string feature in featureList) + ConnectionPolicy policy = new ConnectionPolicy() { - if (feature.Equals(nameof(UserAgentFeatureFlags.PerPartitionCircuitBreaker))) - { - cosmosClientOptions.EnablePartitionLevelCircuitBreaker = true; - } - else if (feature.Equals(nameof(UserAgentFeatureFlags.PerPartitionAutomaticFailover))) - { - cosmosClientOptions.EnablePartitionLevelFailover = true; - } - } + EnablePartitionLevelCircuitBreaker = ppcb, + EnablePartitionLevelFailover = ppaf + }; + + CosmosClient cosmosClient = cosmosClientBuilder.Build(new MockDocumentClient(policy)); - cosmosClientOptions.ApplicationRegion = Regions.WestUS; + CosmosClientOptions cosmosClientOptions = cosmosClient.ClientOptions; + if (appName) { Assert.AreEqual(userAgentSuffix, cosmosClientOptions.ApplicationName); + cosmosClient.DocumentClient.ConnectionPolicy.UserAgentContainer.AppendFeatures(cosmosClientOptions.ApplicationName); } else { Assert.IsNull(cosmosClientOptions.ApplicationName); } - Cosmos.UserAgentContainer userAgentContainer = cosmosClientOptions.CreateUserAgentContainerWithFeatures(clientId: 0); - Console.WriteLine(userAgentContainer.UserAgent); + cosmosClient.DocumentClient.ConnectionPolicy.UserAgentContainer.AppendFeatures(cosmosClient.DocumentClient.GetUserAgentFeatures()); + + string userAgent = cosmosClient.DocumentClient.ConnectionPolicy.UserAgentContainer.UserAgent; + Console.WriteLine(userAgent); if (appName) { - Assert.IsTrue(userAgentContainer.UserAgent.EndsWith(userAgentSuffix)); + Assert.IsTrue(userAgent.EndsWith(userAgentSuffix)); } else { - Assert.IsTrue(userAgentContainer.UserAgent.EndsWith(expectedHexStringPostFix)); + Assert.IsTrue(userAgent.EndsWith(expectedHexStringPostFix)); } - - Assert.IsTrue(userAgentContainer.UserAgent.StartsWith(expectedValue)); - ConnectionPolicy connectionPolicy = cosmosClientOptions.GetConnectionPolicy(clientId: 0); - Assert.IsTrue(connectionPolicy.UserAgentContainer.UserAgent.StartsWith(expectedValue)); - Assert.IsTrue(connectionPolicy.UserAgentContainer.UserAgent.Contains(expectedHexStringPostFix)); + Assert.IsTrue(userAgent.StartsWith(expectedValue)); + Assert.IsTrue(userAgent.Contains(expectedHexStringPostFix)); + if (appName) { - Assert.IsTrue(connectionPolicy.UserAgentContainer.UserAgent.EndsWith(userAgentSuffix)); + Assert.IsTrue(userAgent.EndsWith(userAgentSuffix)); } else { - Assert.IsTrue(connectionPolicy.UserAgentContainer.UserAgent.EndsWith(expectedHexStringPostFix)); + Assert.IsTrue(userAgent.EndsWith(expectedHexStringPostFix)); } } @@ -1202,62 +1189,6 @@ public void TestServerCertificatesValidationWithDisableSSLFlagTrue(string connSt #nullable disable } - [TestMethod] - public void PPAFClientApplicationRegionCreationTest() - { - CosmosClientOptions cosmosClientOptions = new CosmosClientOptions - { - ApplicationRegion = Regions.WestUS2, - EnablePartitionLevelFailover = true - }; - - CosmosClient cosmosClient = new CosmosClient(ConnectionString, cosmosClientOptions); - Assert.AreEqual(Regions.WestUS2, cosmosClient.ClientOptions.ApplicationRegion); - Assert.IsTrue(cosmosClient.ClientOptions.EnablePartitionLevelFailover); - } - - [TestMethod] - public void PPAFClientApplicationPreferredRegionCreationTest() - { - CosmosClientOptions cosmosClientOptions = new CosmosClientOptions - { - ApplicationPreferredRegions = new List { Regions.WestUS2, Regions.EastUS2 }, - EnablePartitionLevelFailover = true - }; - - CosmosClient cosmosClient = new CosmosClient(ConnectionString, cosmosClientOptions); - Assert.AreEqual(Regions.WestUS2, cosmosClient.ClientOptions.ApplicationPreferredRegions[0]); - Assert.AreEqual(Regions.EastUS2, cosmosClient.ClientOptions.ApplicationPreferredRegions[1]); - Assert.IsTrue(cosmosClient.ClientOptions.EnablePartitionLevelFailover); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentException))] - public void PPAFClientAppRegionAndAppPreferredRegionTest() - { - CosmosClientOptions cosmosClientOptions = new CosmosClientOptions - { - EnablePartitionLevelFailover = true, - ApplicationPreferredRegions = new List { Regions.WestUS2, Regions.EastUS2 }, - ApplicationRegion = Regions.AustraliaCentral - }; - - _ = new CosmosClient(ConnectionString, cosmosClientOptions); - } - - [TestMethod] - public void PPAFClientNoRegionsTest() - { - CosmosClientOptions cosmosClientOptions = new CosmosClientOptions - { - EnablePartitionLevelFailover = true - }; - - CosmosClient cosmosClient = new(ConnectionString, cosmosClientOptions); - - Assert.IsNotNull(cosmosClient); - } - private class TestWebProxy : IWebProxy { public ICredentials Credentials { get; set; } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosJsonSerializerUnitTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosJsonSerializerUnitTests.cs index e664746a04..1ebff95eec 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosJsonSerializerUnitTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosJsonSerializerUnitTests.cs @@ -55,7 +55,7 @@ public void ValidatePropertySerialization() string id = "testId"; this.TestProperty( id, - $@"{{""id"":""{id}"",""writableLocations"":[],""readableLocations"":[],""userConsistencyPolicy"":null,""addresses"":null,""userReplicationPolicy"":null,""systemReplicationPolicy"":null,""readPolicy"":null,""queryEngineConfiguration"":null,""enableMultipleWriteLocations"":false}}"); + $@"{{""id"":""{id}"",""writableLocations"":[],""readableLocations"":[],""userConsistencyPolicy"":null,""addresses"":null,""userReplicationPolicy"":null,""systemReplicationPolicy"":null,""readPolicy"":null,""queryEngineConfiguration"":null,""enableMultipleWriteLocations"":false,""enablePerPartitionFailoverBehavior"":null}}"); this.TestProperty( id, diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosSerializerCoreTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosSerializerCoreTests.cs index 9c748eb790..7b18b25518 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosSerializerCoreTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosSerializerCoreTests.cs @@ -143,7 +143,7 @@ public void ValidateCustomSerializerNotUsedForInternalTypes() this.TestProperty( serializerCore, id, - $@"{{""id"":""{id}"",""writableLocations"":[],""readableLocations"":[],""userConsistencyPolicy"":null,""addresses"":null,""userReplicationPolicy"":null,""systemReplicationPolicy"":null,""readPolicy"":null,""queryEngineConfiguration"":null,""enableMultipleWriteLocations"":false}}"); + $@"{{""id"":""{id}"",""writableLocations"":[],""readableLocations"":[],""userConsistencyPolicy"":null,""addresses"":null,""userReplicationPolicy"":null,""systemReplicationPolicy"":null,""readPolicy"":null,""queryEngineConfiguration"":null,""enableMultipleWriteLocations"":false,""enablePerPartitionFailoverBehavior"":null}}"); this.TestProperty( serializerCore, diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/PartitionKeyRangeFailoverTests/GlobalPartitionEndpointManagerTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/PartitionKeyRangeFailoverTests/GlobalPartitionEndpointManagerTests.cs index 114428297b..433250e811 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/PartitionKeyRangeFailoverTests/GlobalPartitionEndpointManagerTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/PartitionKeyRangeFailoverTests/GlobalPartitionEndpointManagerTests.cs @@ -24,6 +24,7 @@ public class GlobalPartitionEndpointManagerTests public async Task TestWriteForbiddenScenarioAsync() { GlobalPartitionEndpointManagerTests.SetupAccountAndCacheOperations( + shouldEnablePPAF: true, out string secondaryRegionNameForUri, out string globalEndpoint, out string secondaryRegionEndpiont, @@ -57,13 +58,12 @@ public async Task TestWriteForbiddenScenarioAsync() CosmosClientOptions cosmosClientOptions = new CosmosClientOptions() { - EnablePartitionLevelFailover = true, ConsistencyLevel = Cosmos.ConsistencyLevel.Strong, ApplicationPreferredRegions = new List() - { - Regions.EastUS, - Regions.WestUS - }, + { + Regions.EastUS, + Regions.WestUS + }, HttpClientFactory = () => new HttpClient(new HttpHandlerHelper(mockHttpHandler.Object)), TransportClientHandlerFactory = (original) => mockTransport.Object, }; @@ -115,6 +115,7 @@ public async Task TestWriteForbiddenScenarioAsync() public async Task CreateItemAsync_WithPreferredRegionsAndServiceUnavailableForFirstPreferredRegion_ShouldRetryAndSucceedToTheNextPreferredRegion() { GlobalPartitionEndpointManagerTests.SetupAccountAndCacheOperations( + shouldEnablePPAF: true, out string secondaryRegionNameForUri, out string globalEndpoint, out string secondaryRegionEndpiont, @@ -148,21 +149,20 @@ public async Task CreateItemAsync_WithPreferredRegionsAndServiceUnavailableForFi CosmosClientOptions cosmosClientOptions = new CosmosClientOptions() { - EnablePartitionLevelFailover = true, ConsistencyLevel = Cosmos.ConsistencyLevel.Strong, ApplicationPreferredRegions = new List() - { - Regions.EastUS, - Regions.WestUS - }, + { + Regions.EastUS, + Regions.WestUS + }, HttpClientFactory = () => new HttpClient(new HttpHandlerHelper(mockHttpHandler.Object)), TransportClientHandlerFactory = (original) => mockTransport.Object, }; using CosmosClient customClient = new CosmosClient( - globalEndpoint, - Convert.ToBase64String(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())), - cosmosClientOptions); + globalEndpoint, + Convert.ToBase64String(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())), + cosmosClientOptions); Container container = customClient.GetContainer(databaseName, containerName); @@ -212,6 +212,7 @@ public void CreateItemAsync_WithNoPreferredRegionsAndServiceUnavailable_ShouldNo TimeSpan explictAvailabilityStrategyThresholdStep = TimeSpan.FromMilliseconds(500); GlobalPartitionEndpointManagerTests.SetupAccountAndCacheOperations( + shouldEnablePPAF: true, out string secondaryRegionNameForUri, out string globalEndpoint, out string secondaryRegionEndpiont, @@ -247,7 +248,6 @@ public void CreateItemAsync_WithNoPreferredRegionsAndServiceUnavailable_ShouldNo CosmosClientOptions cosmosClientOptions = new CosmosClientOptions() { - EnablePartitionLevelFailover = true, ConsistencyLevel = Cosmos.ConsistencyLevel.Strong, HttpClientFactory = () => new HttpClient(new HttpHandlerHelper(mockHttpHandler.Object)), TransportClientHandlerFactory = (original) => mockTransport.Object, @@ -268,10 +268,10 @@ public void CreateItemAsync_WithNoPreferredRegionsAndServiceUnavailable_ShouldNo Assert.IsNotNull(cosmosClient, message: "ApplicationPreferredRegions or ApplicationRegion is no longer mandatory fields, hence the client initialization should succeed."); - Assert.IsNotNull(cosmosClient.ClientOptions.AvailabilityStrategy); + Assert.IsNotNull(cosmosClient.DocumentClient.ConnectionPolicy.AvailabilityStrategy); + + CrossRegionHedgingAvailabilityStrategy crossRegionHedgingStrategy = (CrossRegionHedgingAvailabilityStrategy)cosmosClient.DocumentClient.ConnectionPolicy.AvailabilityStrategy; - CrossRegionHedgingAvailabilityStrategy crossRegionHedgingStrategy = (CrossRegionHedgingAvailabilityStrategy)cosmosClient.ClientOptions.AvailabilityStrategy; - Assert.IsNotNull(crossRegionHedgingStrategy); if (isExplictAvailabilityStrategyProvided) @@ -293,6 +293,7 @@ public void CreateItemAsync_WithNoPreferredRegionsAndServiceUnavailable_ShouldNo public async Task TestRequestTimeoutExceptionScenarioAsync() { GlobalPartitionEndpointManagerTests.SetupAccountAndCacheOperations( + shouldEnablePPAF: true, out string secondaryRegionNameForUri, out string globalEndpoint, out string secondaryRegionEndpiont, @@ -326,13 +327,12 @@ public async Task TestRequestTimeoutExceptionScenarioAsync() CosmosClientOptions cosmosClientOptions = new CosmosClientOptions() { - EnablePartitionLevelFailover = true, ConsistencyLevel = Cosmos.ConsistencyLevel.Strong, ApplicationPreferredRegions = new List() - { - Regions.EastUS, - Regions.WestUS - }, + { + Regions.EastUS, + Regions.WestUS + }, HttpClientFactory = () => new HttpClient(new HttpHandlerHelper(mockHttpHandler.Object)), TransportClientHandlerFactory = (original) => mockTransport.Object, }; @@ -386,6 +386,7 @@ public async Task TestRequestTimeoutExceptionScenarioAsync() } private static void SetupAccountAndCacheOperations( + bool shouldEnablePPAF, out string secondaryRegionNameForUri, out string globalEndpoint, out string secondaryRegionEndpiont, @@ -439,7 +440,8 @@ private static void SetupAccountAndCacheOperations( endpoint: globalEndpointUri.ToString(), accountName: accountName, writeRegions: writeRegion, - readRegions: readRegions); + readRegions: readRegions, + shouldEnablePPAF: shouldEnablePPAF); MockSetupsHelper.SetupContainerProperties( mockHttpHandler: mockHttpHandler, diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/PartitionKeyRangeFailoverTests/MockSetupsHelper.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/PartitionKeyRangeFailoverTests/MockSetupsHelper.cs index 160ed58548..4356df6d50 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/PartitionKeyRangeFailoverTests/MockSetupsHelper.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/PartitionKeyRangeFailoverTests/MockSetupsHelper.cs @@ -29,12 +29,14 @@ public static void SetupStrongAccountProperties( string accountName, string endpoint, IList writeRegions, - IList readRegions) + IList readRegions, + bool shouldEnablePPAF) { HttpResponseMessage httpResponseMessage = MockSetupsHelper.CreateStrongAccount( accountName, writeRegions, - readRegions); + readRegions, + shouldEnablePPAF); Uri endpointUri = new Uri(endpoint); mockHttpClientHandler.Setup(x => x.SendAsync( @@ -106,7 +108,8 @@ public static Uri SetupSingleRegionAccount( public static HttpResponseMessage CreateStrongAccount( string accountName, IList writeRegions, - IList readRegions) + IList readRegions, + bool shouldEnablePPAF = false) { AccountProperties accountProperties = new AccountProperties() { @@ -114,6 +117,7 @@ public static HttpResponseMessage CreateStrongAccount( WriteLocationsInternal = new Collection(writeRegions), ReadLocationsInternal = new Collection(readRegions), EnableMultipleWriteLocations = writeRegions.Count > 1, + EnablePartitionLevelFailover = shouldEnablePPAF, Consistency = new AccountConsistency() { DefaultConsistencyLevel = Cosmos.ConsistencyLevel.Strong diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/PartitionKeyRangeFailoverTests/RegionFailoverTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/PartitionKeyRangeFailoverTests/RegionFailoverTests.cs index dfd5a0c23a..f8bddc530c 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/PartitionKeyRangeFailoverTests/RegionFailoverTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/PartitionKeyRangeFailoverTests/RegionFailoverTests.cs @@ -103,11 +103,11 @@ public async Task TestHttpRequestExceptionScenarioAsync() count++; if (count < 2) { - return Task.FromResult(MockSetupsHelper.CreateStrongAccount(accountName, writeRegion, readRegions)); + return Task.FromResult(MockSetupsHelper.CreateStrongAccount(accountName, writeRegion, readRegions, shouldEnablePPAF: true)); } else { - return Task.FromResult(MockSetupsHelper.CreateStrongAccount(accountName, writeRegionFailedOver, readRegionsFailedOver)); + return Task.FromResult(MockSetupsHelper.CreateStrongAccount(accountName, writeRegionFailedOver, readRegionsFailedOver, shouldEnablePPAF: true)); } }); @@ -156,7 +156,6 @@ public async Task TestHttpRequestExceptionScenarioAsync() CosmosClientOptions cosmosClientOptions = new CosmosClientOptions() { - EnablePartitionLevelFailover = true, ConsistencyLevel = Cosmos.ConsistencyLevel.Strong, ApplicationPreferredRegions = new List() {