Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<ClientOfficialVersion>3.57.0</ClientOfficialVersion>
<ClientPreviewVersion>3.58.0</ClientPreviewVersion>
<ClientPreviewSuffixVersion>preview.0</ClientPreviewSuffixVersion>
<DirectVersion>3.41.3</DirectVersion>
Comment thread
aavasthy marked this conversation as resolved.
<DirectVersion>3.42.0</DirectVersion>
<FaultInjectionVersion>1.0.0</FaultInjectionVersion>
<FaultInjectionSuffixVersion>beta.0</FaultInjectionSuffixVersion>
<EncryptionOfficialVersion>2.0.5</EncryptionOfficialVersion>
Expand Down
5 changes: 1 addition & 4 deletions Microsoft.Azure.Cosmos/src/DocumentClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6792,8 +6792,6 @@ private void InitializeDirectConnectivity(IStoreClientFactory storeClientFactory

private void CreateStoreModel(bool subscribeRntbdStatus)
{
AccountConfigurationProperties accountConfigurationProperties = new (EnableNRegionSynchronousCommit: this.accountServiceConfiguration.AccountProperties.EnableNRegionSynchronousCommit);

//EnableReadRequestsFallback, if not explicity set on the connection policy,
//is false if the account's consistency is bounded staleness,
//and true otherwise.
Expand All @@ -6808,8 +6806,7 @@ private void CreateStoreModel(bool subscribeRntbdStatus)
this.UseMultipleWriteLocations && (this.accountServiceConfiguration.DefaultConsistencyLevel != Documents.ConsistencyLevel.Strong),
true,
enableReplicaValidation: this.isReplicaAddressValidationEnabled,
sessionRetryOptions: this.ConnectionPolicy.SessionRetryOptions,
accountConfigurationProperties: accountConfigurationProperties);
sessionRetryOptions: this.ConnectionPolicy.SessionRetryOptions);

if (subscribeRntbdStatus)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Microsoft.Azure.Cosmos
using System.Threading.Tasks;
using Microsoft.Azure.Documents;

internal class CosmosAccountServiceConfiguration : IServiceConfigurationReader
internal class CosmosAccountServiceConfiguration : IServiceConfigurationReaderVnext
{
private Func<Task<AccountProperties>> accountPropertiesTaskFunc { get; }

Expand Down Expand Up @@ -53,6 +53,8 @@ public CosmosAccountServiceConfiguration(Func<Task<AccountProperties>> accountPr

public string SubscriptionId => throw new NotImplementedException();

public bool EnableNRegionSynchronousCommit => this.AccountProperties.EnableNRegionSynchronousCommit;

public async Task InitializeAsync()
{
if (this.AccountProperties == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http;
Expand Down Expand Up @@ -364,5 +365,105 @@ public async Task CreateAndInitializeAsync_WithValidDatabaseAndInvalidContainer_
Assert.IsNotNull(ce);
Assert.AreEqual(HttpStatusCode.NotFound, ce.StatusCode);
}

/// <summary>
/// Test to validate write item operations with transport interceptor that modifies
/// GlobalNRegionCommittedGLSN header and HTTP interceptor that sets EnableNRegionSynchronousCommit
/// in AccountProperties response.
/// </summary>
[TestMethod]
[Owner("aavasthy")]
public async Task CreateAndInitializeAsync_WriteItemOperationWithNRegionCommitTest()
{
// Custom GlobalNRegionCommittedGLSN value to inject
const long customGlobalNRegionCommittedGLSN = 100;

// HTTP handler to intercept AccountProperties response and set EnableNRegionSynchronousCommit = true
HttpClientHandlerHelper httpClientHandlerHelper = new HttpClientHandlerHelper
{
ResponseIntercepter = async (response, request) =>
{
if (request.RequestUri.AbsolutePath.EndsWith("/", StringComparison.OrdinalIgnoreCase) ||
request.RequestUri.AbsolutePath.Equals(string.Empty))
{
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
Newtonsoft.Json.Linq.JObject accountJson = Newtonsoft.Json.Linq.JObject.Parse(content);

accountJson[Constants.Properties.EnableNRegionSynchronousCommit] = true;

string modifiedContent = accountJson.ToString();
response.Content = new StringContent(modifiedContent, System.Text.Encoding.UTF8, "application/json");
}
}
return response;
}
};

await this.TestInit(
customizeClientBuilder: (builder) =>
{
builder.WithConnectionModeDirect();
builder.WithHttpClientFactory(() => new HttpClient(httpClientHandlerHelper));
builder.WithTransportClientHandlerFactory(transportClient =>
new TransportClientHelper.TransportClientWrapper(
client: transportClient,
interceptorAfterResult: (request, storeResponse) =>
{
// Override GlobalNRegionCommittedGLSN header in the response for Document operations
if (request.ResourceType == ResourceType.Document)
{
storeResponse.Headers.Set(
WFConstants.BackendHeaders.GlobalNRegionCommittedGLSN,
customGlobalNRegionCommittedGLSN.ToString(CultureInfo.InvariantCulture));
}
return storeResponse;
}));
});

string containerName = "NRegionCommitTestContainer_" + Guid.NewGuid().ToString("N");
ContainerResponse containerResponse = await this.database.CreateContainerAsync(
new ContainerProperties(id: containerName, partitionKeyPath: PartitionKey),
cancellationToken: this.cancellationToken);
Assert.IsNotNull(containerResponse);

Container container = containerResponse.Container;

try
{
for (int i = 0; i < 2; i++)
{
ToDoActivity item = new()
{
id = Guid.NewGuid().ToString(),
pk = "testPartition",
description = $"Test item {i}",
};

// Act
ItemResponse<ToDoActivity> writeResponse = await container.CreateItemAsync(
item: item,
partitionKey: new Cosmos.PartitionKey(item.pk));

// Assert
Assert.AreEqual(HttpStatusCode.Created, writeResponse.StatusCode);

// Assert: Verify GlobalNRegionCommittedGLSN is present in diagnostics with value 100
string diagnostics = writeResponse.Diagnostics.ToString();

Assert.IsTrue(
diagnostics.Contains($"\"GlobalNRegionCommittedGLSN\":{customGlobalNRegionCommittedGLSN}") ||
diagnostics.Contains($"\"GlobalNRegionCommittedGLSN\": {customGlobalNRegionCommittedGLSN}"),
$"Expected GlobalNRegionCommittedGLSN to be {customGlobalNRegionCommittedGLSN} in diagnostics. Actual diagnostics: {diagnostics}");

}
}
finally
{
// Cleanup: Delete the test container
await container.DeleteContainerAsync();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -276,113 +276,6 @@ private void TestRetryOnThrottled(int? numberOfRetries)
Assert.IsTrue(throttled);
}

[TestMethod]
Comment thread
aavasthy marked this conversation as resolved.
[DataRow(false, DisplayName = "NRegion Synchronous commit is disabled for the account")]
[DataRow(true, DisplayName = "NRegion Synchronous commit is enabled for the account")]
public void EnableNRegionSynchronousCommit_PassedToStoreClient(bool nRegionCommitEnabled)
{

StoreClient storeClient = new StoreClient(
new Mock<IAddressResolver>().Object,
new SessionContainer(string.Empty),
new Mock<IServiceConfigurationReader>().Object,
new Mock<IAuthorizationTokenProvider>().Object,
Protocol.Tcp,
new Mock<TransportClient>().Object);
// Arrange
Mock<IStoreClientFactory> mockStoreClientFactory = new Mock<IStoreClientFactory>();
mockStoreClientFactory.Setup(f => f.CreateStoreClient(
It.IsAny<IAddressResolver>(),
It.IsAny<ISessionContainer>(),
It.IsAny<IServiceConfigurationReader>(),
It.IsAny<IAuthorizationTokenProvider>(),
It.IsAny<bool>(),
It.IsAny<bool>(),
It.IsAny<bool>(),
It.IsAny<bool>(),
It.IsAny<bool>(),
It.IsAny<bool>(),
It.IsAny<AccountConfigurationProperties>(),
It.IsAny<ISessionRetryOptions>()
)).Returns(storeClient);

DocumentClient documentClient = new DocumentClient(
new Uri("https://localhost:8081"),
new Mock<AuthorizationTokenProvider>().Object,
new EventHandler<SendingRequestEventArgs>((s, e) => { }),
new ConnectionPolicy(),
null, // desiredConsistencyLevel
null, // serializerSettings
ApiType.None,
new EventHandler<ReceivedResponseEventArgs>((s, e) => { }),
null, // handler
new Mock<ISessionContainer>().Object,
null, // enableCpuMonitor
new Func<TransportClient, TransportClient>(tc => tc),
mockStoreClientFactory.Object,
false, // isLocalQuorumConsistency
"testClientId",
new RemoteCertificateValidationCallback((sender, certificate, chain, sslPolicyErrors) => true),
new Mock<CosmosClientTelemetryOptions>().Object,
new Mock<IChaosInterceptorFactory>().Object,
true // enableAsyncCacheExceptionNoSharing
);

AccountProperties accountProperties = new AccountProperties
{
// Set the property to true for test
EnableNRegionSynchronousCommit = nRegionCommitEnabled,
};

AccountConsistency ac = new AccountConsistency();
ac.DefaultConsistencyLevel = (Cosmos.ConsistencyLevel) ConsistencyLevel.Session;
accountProperties.Consistency = ac;

Func<Task<AccountProperties>> getDatabaseAccountFn = () =>
// When called with any Uri, return the expected AccountProperties
Task.FromResult(accountProperties);

CosmosAccountServiceConfiguration accountServiceConfiguration = new CosmosAccountServiceConfiguration(
getDatabaseAccountFn);

typeof(CosmosAccountServiceConfiguration)
.GetProperty("AccountProperties", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)
.SetValue(accountServiceConfiguration, accountProperties);

//Inject the accountServiceConfiguration into the DocumentClient via reflection.
typeof(DocumentClient)
.GetProperty("accountServiceConfiguration", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)
.SetValue(documentClient, accountServiceConfiguration);


typeof(DocumentClient)
.GetField("storeClientFactory", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)
.SetValue(documentClient, mockStoreClientFactory.Object);

// Act: Call the private method via reflection
typeof(DocumentClient)
.GetMethod("CreateStoreModel", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)
.Invoke(documentClient, new object[] { true });

// Assert: Verify the correct value was passed
mockStoreClientFactory.Verify(f =>
f.CreateStoreClient(
It.IsAny<IAddressResolver>(),
It.IsAny<ISessionContainer>(),
It.IsAny<IServiceConfigurationReader>(),
It.IsAny<IAuthorizationTokenProvider>(),
It.IsAny<bool>(),
It.IsAny<bool>(),
It.IsAny<bool>(),
It.IsAny<bool>(),
It.IsAny<bool>(),
It.IsAny<bool>(),
It.Is<AccountConfigurationProperties>(config => config.EnableNRegionSynchronousCommit == accountProperties.EnableNRegionSynchronousCommit),
It.IsAny<ISessionRetryOptions>()),
Times.Once,
"EnableNRegionSynchronousCommit was not passed correctly to AccountConfigurationProperties and StoreClient.");
}

private DocumentClientException CreateTooManyRequestException(int retryAfterInMilliseconds)
{
HttpResponseMessage responseMessage = new HttpResponseMessage();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -568,8 +568,7 @@ private async Task ValidateConnectTimeoutTriggersClientRetryPolicyAsync(
useMultipleWriteLocations: useMultipleWriteLocations,
detectClientConnectivityIssues: true,
disableRetryWithRetryPolicy: false,
enableReplicaValidation: false,
accountConfigurationProperties: null);
enableReplicaValidation: false);

// Reducing retry timeout to avoid long-running tests
replicatedResourceClient.GoneAndRetryWithRetryTimeoutInSecondsOverride = 1;
Expand Down
Loading
Loading