Skip to content

Commit 745c596

Browse files
authored
[Thin Client Integration]: Adds empty string for RegionalDatabaseAccount parameter while creating RNTBD request. (#5471)
# Pull Request Template ## Description Starting direct version 3.41.0, we will need to pass empty string for regionalDatabaseAccountName to serialize the request for proxy. ThinProxy has support of retrieving regionalDatabaseAccountName when its empty. Instead of sending globalDatabaseAccountName send empty string. The new contract in TransportSerialization: https://msdata.visualstudio.com/CosmosDB/_git/CosmosDB/commit/3a7ef7e72685727de7762dd6769042cd765f7397?path=/Product/Microsoft.Azure.Documents/SharedFiles/Rntbd2/TransportSerialization.cs&version=GBmaster&line=112&lineEnd=113&lineStartColumn=1&lineEndColumn=1&type=2&lineStyle=plain&_a=files ## Type of change Please delete options that are not relevant. - [X] Bug fix (non-breaking change which fixes an issue) ## Closing issues To automatically close an issue: closes #5426
1 parent 14c1265 commit 745c596

3 files changed

Lines changed: 78 additions & 9 deletions

File tree

Microsoft.Azure.Cosmos/src/ThinClientTransportSerializer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ public static async Task<Stream> SerializeProxyRequestAsync(
113113
activityId,
114114
bufferProvider.Provider,
115115
accountName,
116-
accountName,
116+
string.Empty,
117117
out _,
118118
out _);
119119

Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ public async Task NegativeCreateItemTest(bool binaryEncodingEnabledInClient)
275275
{
276276
Assert.AreEqual(999999, ce.SubStatusCode);
277277
string exception = ce.ToString();
278-
Assert.IsTrue(exception.StartsWith("Microsoft.Azure.Cosmos.CosmosException : Response status code does not indicate success: Forbidden (403); Substatus: 999999; "));
278+
Assert.IsTrue(exception.Contains("Response status code does not indicate success: Forbidden (403); Substatus: 999999; "));
279279
string diagnostics = ce.Diagnostics.ToString();
280280
Assert.IsTrue(diagnostics.Contains("999999"));
281281
CosmosItemTests.ValidateCosmosException(ce);

Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemThinClientTests.cs

Lines changed: 76 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests
1313
using System.Text.Json;
1414
using System.Text.Json.Serialization;
1515
using System.Threading.Tasks;
16+
using global::Azure;
1617
using global::Azure.Core;
1718
using Microsoft.Azure.Cosmos.Fluent;
1819
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -113,6 +114,76 @@ private async Task<List<TestObject>> CreateItemsSafeAsync(IEnumerable<TestObject
113114
return itemsCreated;
114115
}
115116

117+
[TestMethod]
118+
[TestCategory("ThinClient")]
119+
public async Task RegionalDatabaseAccountNameIsEmptyInPayload()
120+
{
121+
byte[] capturedPayload = null;
122+
Environment.SetEnvironmentVariable(ConfigurationManager.ThinClientModeEnabled, "True");
123+
this.connectionString = Environment.GetEnvironmentVariable("COSMOSDB_THINCLIENT");
124+
125+
// Initialize the serializer locally
126+
JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions
127+
{
128+
PropertyNamingPolicy = null,
129+
PropertyNameCaseInsensitive = true,
130+
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
131+
};
132+
CosmosSystemTextJsonSerializer serializer = new CosmosSystemTextJsonSerializer(jsonSerializerOptions);
133+
134+
CosmosClientBuilder builder = new CosmosClientBuilder(this.connectionString)
135+
.WithConnectionModeGateway()
136+
.WithCustomSerializer(serializer)
137+
.WithSendingRequestEventArgs(async (sender, e) =>
138+
{
139+
if (e.HttpRequest.Version == new Version(2, 0))
140+
{
141+
if (e.HttpRequest.Content != null)
142+
{
143+
capturedPayload = await e.HttpRequest.Content.ReadAsByteArrayAsync();
144+
}
145+
}
146+
});
147+
148+
using CosmosClient client = builder.Build();
149+
string uniqueDbName = "TestRegional_" + Guid.NewGuid().ToString();
150+
Database database = await client.CreateDatabaseIfNotExistsAsync(uniqueDbName);
151+
string uniqueContainerName = "TestRegionalContainer_" + Guid.NewGuid().ToString();
152+
Container container = await database.CreateContainerIfNotExistsAsync(uniqueContainerName, "/pk");
153+
154+
string pk = "pk_regional";
155+
TestObject testItem = this.GenerateItems(pk).First();
156+
157+
// Act
158+
ItemResponse<TestObject> response = await container.CreateItemAsync(testItem, new PartitionKey(testItem.Pk));
159+
Assert.AreEqual(HttpStatusCode.Created, response.StatusCode);
160+
161+
// Assert
162+
Assert.IsNotNull(capturedPayload, "The request payload was not captured.");
163+
164+
165+
// The RNTBD protocol serializes an empty string as a token with a length of 0.
166+
// For `regionalDatabaseAccountName`, which is a SmallString (type 0x02), this is
167+
// serialized as two bytes: 0x02 (type) and 0x00 (length).
168+
// This byte pair represents an empty string value in RNTBD’s small-string encoding.
169+
byte[] emptyStringToken = { 0x02, 0x00 };
170+
171+
bool foundEmptyStringToken = false;
172+
for (int i = 0; i <= capturedPayload.Length - emptyStringToken.Length; i++)
173+
{
174+
if (capturedPayload[i] == emptyStringToken[0] && capturedPayload[i + 1] == emptyStringToken[1])
175+
{
176+
foundEmptyStringToken = true;
177+
break;
178+
}
179+
}
180+
181+
Assert.IsTrue(foundEmptyStringToken, "The RNTBD payload should contain a token representing an empty string for the regional account name.");
182+
183+
// Cleanup
184+
await database.DeleteAsync();
185+
}
186+
116187
[TestMethod]
117188
[TestCategory("ThinClient")]
118189
public async Task HttpRequestVersionIsTwoPointZeroWhenUsingThinClientMode()
@@ -173,12 +244,9 @@ public async Task CreateItemsTest()
173244
public async Task CreateItemsTestWithThinClientFlagEnabledAndAccountDisabled()
174245
{
175246
Environment.SetEnvironmentVariable(ConfigurationManager.ThinClientModeEnabled, "True");
176-
string connectionString = ConfigurationManager.GetEnvironmentVariable<string>("COSMOSDB_MULTI_REGION", string.Empty);
177-
178-
if (string.IsNullOrEmpty(connectionString))
179-
{
180-
Assert.Fail("Set environment variable COSMOSDB_MULTI_REGION to run the tests");
181-
}
247+
string authKey = Utils.ConfigurationManager.AppSettings["MasterKey"];
248+
string endpoint = Utils.ConfigurationManager.AppSettings["GatewayEndpoint"];
249+
AzureKeyCredential masterKeyCredential = new AzureKeyCredential(authKey);
182250

183251
JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions
184252
{
@@ -189,7 +257,8 @@ public async Task CreateItemsTestWithThinClientFlagEnabledAndAccountDisabled()
189257
this.cosmosSystemTextJsonSerializer = new MultiRegionSetupHelpers.CosmosSystemTextJsonSerializer(jsonSerializerOptions);
190258

191259
this.client = new CosmosClient(
192-
connectionString,
260+
endpoint,
261+
masterKeyCredential,
193262
new CosmosClientOptions()
194263
{
195264
ConnectionMode = ConnectionMode.Gateway,

0 commit comments

Comments
 (0)