diff --git a/Microsoft.Azure.Cosmos/src/DistributedTransaction/DistributedTransactionOperationResult.cs b/Microsoft.Azure.Cosmos/src/DistributedTransaction/DistributedTransactionOperationResult.cs index de63261e1e..257c29b93a 100644 --- a/Microsoft.Azure.Cosmos/src/DistributedTransaction/DistributedTransactionOperationResult.cs +++ b/Microsoft.Azure.Cosmos/src/DistributedTransaction/DistributedTransactionOperationResult.cs @@ -140,7 +140,7 @@ internal static DistributedTransactionOperationResult FromJson(JsonElement json) { DistributedTransactionOperationResult result = JsonSerializer.Deserialize(json, DistributedTransactionOperationResult.CaseInsensitiveOptions); - if (json.TryGetProperty("resourceBody", out JsonElement resourceBody) + if (json.TryGetProperty(DistributedTransactionSerializer.ResourceBody, out JsonElement resourceBody) && resourceBody.ValueKind != JsonValueKind.Undefined && resourceBody.ValueKind != JsonValueKind.Null) { diff --git a/Microsoft.Azure.Cosmos/src/DistributedTransaction/DistributedTransactionSerializer.cs b/Microsoft.Azure.Cosmos/src/DistributedTransaction/DistributedTransactionSerializer.cs index b5dd00ba7d..d421c1fb1d 100644 --- a/Microsoft.Azure.Cosmos/src/DistributedTransaction/DistributedTransactionSerializer.cs +++ b/Microsoft.Azure.Cosmos/src/DistributedTransaction/DistributedTransactionSerializer.cs @@ -16,6 +16,20 @@ namespace Microsoft.Azure.Cosmos /// internal static class DistributedTransactionSerializer { + internal const string Operations = "operations"; + internal const string DatabaseName = "databaseName"; + internal const string CollectionName = "collectionName"; + internal const string Id = "id"; + internal const string CollectionResourceId = "collectionResourceId"; + internal const string DatabaseResourceId = "databaseResourceId"; + internal const string PartitionKey = "partitionKey"; + internal const string Index = "index"; + internal const string ResourceBody = "resourceBody"; + internal const string SessionToken = "sessionToken"; + internal const string ETag = "ifMatch"; + internal const string OperationType = "operationType"; + internal const string ResourceType = "resourceType"; + /// /// Serializes a distributed transaction request body to a JSON stream. /// The body contains only the operations array. Other metadata like idempotencyToken, @@ -32,7 +46,7 @@ public static MemoryStream SerializeRequest(IReadOnlyList(resourceBody.GetRawText()); Assert.AreEqual(doc.id, actualDoc.id); @@ -661,10 +661,10 @@ public async Task ReplaceItemStream_ValidDocument_SerializedAsReplaceOperation() Assert.IsTrue(response.IsSuccessStatusCode); using JsonDocument requestJson = JsonDocument.Parse(handler.CapturedRequestBody); - JsonElement operation = requestJson.RootElement.GetProperty("operations")[0]; - Assert.AreEqual(OperationType.Replace.ToString(), operation.GetProperty("operationType").GetString()); - Assert.AreEqual(doc.id, operation.GetProperty("id").GetString()); - JsonElement resourceBody = operation.GetProperty("resourceBody"); + JsonElement operation = requestJson.RootElement.GetProperty(DistributedTransactionSerializer.Operations)[0]; + Assert.AreEqual(OperationType.Replace.ToString(), operation.GetProperty(DistributedTransactionSerializer.OperationType).GetString()); + Assert.AreEqual(doc.id, operation.GetProperty(DistributedTransactionSerializer.Id).GetString()); + JsonElement resourceBody = operation.GetProperty(DistributedTransactionSerializer.ResourceBody); Assert.AreEqual(JsonValueKind.Object, resourceBody.ValueKind); ToDoActivity actualDoc = JsonSerializer.Deserialize(resourceBody.GetRawText()); Assert.AreEqual(doc.id, actualDoc.id); @@ -692,9 +692,9 @@ public async Task PatchItemStream_ValidPatch_SerializedAsPatchOperation() Assert.IsTrue(response.IsSuccessStatusCode); using JsonDocument requestJson = JsonDocument.Parse(handler.CapturedRequestBody); - JsonElement operation = requestJson.RootElement.GetProperty("operations")[0]; - Assert.AreEqual(OperationType.Patch.ToString(), operation.GetProperty("operationType").GetString()); - Assert.AreEqual("patch-id", operation.GetProperty("id").GetString()); + JsonElement operation = requestJson.RootElement.GetProperty(DistributedTransactionSerializer.Operations)[0]; + Assert.AreEqual(OperationType.Patch.ToString(), operation.GetProperty(DistributedTransactionSerializer.OperationType).GetString()); + Assert.AreEqual("patch-id", operation.GetProperty(DistributedTransactionSerializer.Id).GetString()); response.Dispose(); } @@ -718,9 +718,9 @@ public async Task UpsertItemStream_ValidDocument_SerializedAsUpsertOperation() Assert.IsTrue(response.IsSuccessStatusCode); using JsonDocument requestJson = JsonDocument.Parse(handler.CapturedRequestBody); - JsonElement operation = requestJson.RootElement.GetProperty("operations")[0]; - Assert.AreEqual(OperationType.Upsert.ToString(), operation.GetProperty("operationType").GetString()); - JsonElement resourceBody = operation.GetProperty("resourceBody"); + JsonElement operation = requestJson.RootElement.GetProperty(DistributedTransactionSerializer.Operations)[0]; + Assert.AreEqual(OperationType.Upsert.ToString(), operation.GetProperty(DistributedTransactionSerializer.OperationType).GetString()); + JsonElement resourceBody = operation.GetProperty(DistributedTransactionSerializer.ResourceBody); Assert.AreEqual(JsonValueKind.Object, resourceBody.ValueKind); ToDoActivity actualDoc = JsonSerializer.Deserialize(resourceBody.GetRawText()); Assert.AreEqual(doc.id, actualDoc.id); @@ -838,14 +838,14 @@ public async Task ValidateReadTransactionRequestStructure() // Assert – request structure Assert.IsNotNull(handler.CapturedRequestBody); using JsonDocument requestJson = JsonDocument.Parse(handler.CapturedRequestBody); - JsonElement operation = requestJson.RootElement.GetProperty("operations")[0]; - - Assert.AreEqual(OperationType.Read.ToString(), operation.GetProperty("operationType").GetString()); - Assert.AreEqual(doc.id, operation.GetProperty("id").GetString()); - Assert.IsTrue(operation.TryGetProperty("databaseName", out _), "databaseName should be present"); - Assert.IsTrue(operation.TryGetProperty("collectionName", out _), "collectionName should be present"); - Assert.IsTrue(operation.TryGetProperty("partitionKey", out _), "partitionKey should be present"); - Assert.IsFalse(operation.TryGetProperty("resourceBody", out _), "resourceBody must NOT be present for read operations"); + JsonElement operation = requestJson.RootElement.GetProperty(DistributedTransactionSerializer.Operations)[0]; + + Assert.AreEqual(OperationType.Read.ToString(), operation.GetProperty(DistributedTransactionSerializer.OperationType).GetString()); + Assert.AreEqual(doc.id, operation.GetProperty(DistributedTransactionSerializer.Id).GetString()); + Assert.IsTrue(operation.TryGetProperty(DistributedTransactionSerializer.DatabaseName, out _), "databaseName should be present"); + Assert.IsTrue(operation.TryGetProperty(DistributedTransactionSerializer.CollectionName, out _), "collectionName should be present"); + Assert.IsTrue(operation.TryGetProperty(DistributedTransactionSerializer.PartitionKey, out _), "partitionKey should be present"); + Assert.IsFalse(operation.TryGetProperty(DistributedTransactionSerializer.ResourceBody, out _), "resourceBody must NOT be present for read operations"); response.Dispose(); } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DistributedTransaction/DistributedTransactionCommitterTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DistributedTransaction/DistributedTransactionCommitterTests.cs index 19bfd8d7cc..d6bf64dcbb 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DistributedTransaction/DistributedTransactionCommitterTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DistributedTransaction/DistributedTransactionCommitterTests.cs @@ -39,7 +39,7 @@ public async Task CommitTransactionAsync_MergesSessionTokensIntoSessionContainer SessionContainer sessionContainer = new SessionContainer("testhost"); string responseJson = BuildDtcResponseJson( - new[] { (statusCode: 201, sessionToken: sessionToken) }); + new[] { (statusCode: 201, sessionToken) }); Mock mockContext = this.CreateMockContext( sessionContainer, @@ -113,8 +113,10 @@ public async Task CommitTransactionAsync_PassesCorrectCollectionToSetSessionToke Mock mockSessionContainer = new Mock(); - MockDocumentClient documentClient = new MockDocumentClient(); - documentClient.sessionContainer = mockSessionContainer.Object; + MockDocumentClient documentClient = new MockDocumentClient + { + sessionContainer = mockSessionContainer.Object + }; ContainerProperties containerProperties1 = ContainerProperties.CreateWithResourceId(collectionRid1); containerProperties1.PartitionKeyPath = "/pk"; @@ -135,14 +137,16 @@ public async Task CommitTransactionAsync_PassesCorrectCollectionToSetSessionToke It.IsAny(), It.IsAny())) .ReturnsAsync(containerProperties2); - ResponseMessage responseMessage = new ResponseMessage(HttpStatusCode.OK); - responseMessage.Content = new MemoryStream( - Encoding.UTF8.GetBytes(BuildDtcResponseJson( - new[] - { - (statusCode: 200, sessionToken: sessionToken), - (statusCode: 200, sessionToken: sessionToken), - }))); + ResponseMessage responseMessage = new ResponseMessage(HttpStatusCode.OK) + { + Content = new MemoryStream( + Encoding.UTF8.GetBytes(BuildDtcResponseJson( + new[] + { + (statusCode: 200, sessionToken), + (statusCode: 200, sessionToken), + }))) + }; mockContext.Setup(c => c.ProcessResourceOperationStreamAsync( It.IsAny(), ResourceType.DistributedTransactionBatch, @@ -209,7 +213,7 @@ public async Task CommitTransactionAsync_SkipsMerge_When404ReadSessionNotAvailab Mock mockContext = this.CreateMockContext( sessionContainer, - responseContent: BuildDtcResponseJson(new[] { (statusCode: 404, subStatusCode: (int?)readSessionNotAvailableSubStatus, sessionToken: sessionToken) }), + responseContent: BuildDtcResponseJson(new[] { (statusCode: 404, subStatusCode: (int?)readSessionNotAvailableSubStatus, sessionToken) }), statusCode: HttpStatusCode.NotFound); List operations = new List @@ -244,7 +248,7 @@ public async Task CommitTransactionAsync_MergesSessionTokens_OnFailureResponse() Mock mockContext = this.CreateMockContext( sessionContainer, - responseContent: BuildDtcResponseJson(new[] { (statusCode: 409, sessionToken: sessionToken) }), + responseContent: BuildDtcResponseJson(new[] { (statusCode: 409, sessionToken) }), statusCode: HttpStatusCode.Conflict); List operations = new List @@ -298,7 +302,7 @@ private static string BuildDtcResponseJson( if (operations[i].sessionToken != null) { - sb.Append($@",""sessionToken"":""{operations[i].sessionToken}"""); + sb.Append($@",""{DistributedTransactionSerializer.SessionToken}"":""{operations[i].sessionToken}"""); } sb.Append('}'); @@ -313,8 +317,10 @@ private Mock CreateMockContext( string responseContent, HttpStatusCode statusCode) { - MockDocumentClient documentClient = new MockDocumentClient(); - documentClient.sessionContainer = sessionContainer; + MockDocumentClient documentClient = new MockDocumentClient + { + sessionContainer = sessionContainer + }; ContainerProperties containerProperties = ContainerProperties.CreateWithResourceId(CollectionResourceId); containerProperties.Id = "TestContainerId"; diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DistributedTransaction/DistributedTransactionSerializerTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DistributedTransaction/DistributedTransactionSerializerTests.cs index 58bc8ea037..3c86724d89 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DistributedTransaction/DistributedTransactionSerializerTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DistributedTransaction/DistributedTransactionSerializerTests.cs @@ -44,13 +44,13 @@ public async Task CreateItem_SerializedBody_HasResourceBody_AndIdField() tx.CreateItem(Database, Container, new PartitionKey("pk"), itemId, new TestItem(itemId))); using JsonDocument doc = JsonDocument.Parse(capturedJson); - JsonElement op = doc.RootElement.GetProperty("operations")[0]; + JsonElement op = doc.RootElement.GetProperty(DistributedTransactionSerializer.Operations)[0]; - Assert.IsTrue(op.TryGetProperty("id", out JsonElement idElement), + Assert.IsTrue(op.TryGetProperty(DistributedTransactionSerializer.Id, out JsonElement idElement), "Create operation must include an 'id' field."); Assert.AreEqual(itemId, idElement.GetString(), "The 'id' field must match the id passed to CreateItem."); - Assert.IsTrue(op.TryGetProperty("resourceBody", out _), + Assert.IsTrue(op.TryGetProperty(DistributedTransactionSerializer.ResourceBody, out _), "Create operation must include a 'resourceBody' field."); } @@ -64,11 +64,11 @@ public async Task ReplaceItem_SerializedBody_HasIdField_AndResourceBody() tx.ReplaceItem(Database, Container, new PartitionKey("pk"), itemId, new TestItem(itemId))); using JsonDocument doc = JsonDocument.Parse(capturedJson); - JsonElement op = doc.RootElement.GetProperty("operations")[0]; + JsonElement op = doc.RootElement.GetProperty(DistributedTransactionSerializer.Operations)[0]; - Assert.IsTrue(op.TryGetProperty("id", out _), + Assert.IsTrue(op.TryGetProperty(DistributedTransactionSerializer.Id, out _), "Replace operation must include an 'id' field."); - Assert.IsTrue(op.TryGetProperty("resourceBody", out _), + Assert.IsTrue(op.TryGetProperty(DistributedTransactionSerializer.ResourceBody, out _), "Replace operation must include a 'resourceBody' field."); } @@ -82,11 +82,11 @@ public async Task DeleteItem_SerializedBody_HasIdField_NoResourceBody() tx.DeleteItem(Database, Container, new PartitionKey("pk"), itemId)); using JsonDocument doc = JsonDocument.Parse(capturedJson); - JsonElement op = doc.RootElement.GetProperty("operations")[0]; + JsonElement op = doc.RootElement.GetProperty(DistributedTransactionSerializer.Operations)[0]; - Assert.IsTrue(op.TryGetProperty("id", out _), + Assert.IsTrue(op.TryGetProperty(DistributedTransactionSerializer.Id, out _), "Delete operation must include an 'id' field."); - Assert.IsFalse(op.TryGetProperty("resourceBody", out _), + Assert.IsFalse(op.TryGetProperty(DistributedTransactionSerializer.ResourceBody, out _), "Delete operation must NOT include a 'resourceBody' field."); } @@ -99,13 +99,13 @@ public async Task UpsertItem_SerializedBody_HasResourceBody_AndIdField() tx.UpsertItem(Database, Container, new PartitionKey("pk"), itemId, new TestItem(itemId))); using JsonDocument doc = JsonDocument.Parse(capturedJson); - JsonElement op = doc.RootElement.GetProperty("operations")[0]; + JsonElement op = doc.RootElement.GetProperty(DistributedTransactionSerializer.Operations)[0]; - Assert.IsTrue(op.TryGetProperty("id", out JsonElement idElement), + Assert.IsTrue(op.TryGetProperty(DistributedTransactionSerializer.Id, out JsonElement idElement), "Upsert operation must include an 'id' field."); Assert.AreEqual(itemId, idElement.GetString(), "The 'id' field must match the id passed to UpsertItem."); - Assert.IsTrue(op.TryGetProperty("resourceBody", out _), + Assert.IsTrue(op.TryGetProperty(DistributedTransactionSerializer.ResourceBody, out _), "Upsert operation must include a 'resourceBody' field."); } @@ -121,9 +121,9 @@ public async Task ReplaceItem_SerializedBody_IdValueMatchesProvided() tx.ReplaceItem(Database, Container, new PartitionKey("pk"), expectedId, new TestItem(expectedId))); using JsonDocument doc = JsonDocument.Parse(capturedJson); - JsonElement op = doc.RootElement.GetProperty("operations")[0]; + JsonElement op = doc.RootElement.GetProperty(DistributedTransactionSerializer.Operations)[0]; - Assert.IsTrue(op.TryGetProperty("id", out JsonElement idElement)); + Assert.IsTrue(op.TryGetProperty(DistributedTransactionSerializer.Id, out JsonElement idElement)); Assert.AreEqual(expectedId, idElement.GetString(), "The serialized 'id' field must equal the id passed to ReplaceItem()."); } @@ -138,9 +138,9 @@ public async Task DeleteItem_SerializedBody_IdValueMatchesProvided() tx.DeleteItem(Database, Container, new PartitionKey("pk"), expectedId)); using JsonDocument doc = JsonDocument.Parse(capturedJson); - JsonElement op = doc.RootElement.GetProperty("operations")[0]; + JsonElement op = doc.RootElement.GetProperty(DistributedTransactionSerializer.Operations)[0]; - Assert.IsTrue(op.TryGetProperty("id", out JsonElement idElement)); + Assert.IsTrue(op.TryGetProperty(DistributedTransactionSerializer.Id, out JsonElement idElement)); Assert.AreEqual(expectedId, idElement.GetString(), "The serialized 'id' field must equal the id passed to DeleteItem()."); } @@ -155,9 +155,9 @@ public async Task CreateItem_SerializedBody_ResourceBodyIsValidJson() tx.CreateItem(Database, Container, new PartitionKey("pk"), "json-check", new TestItem("json-check"))); using JsonDocument doc = JsonDocument.Parse(capturedJson); - JsonElement op = doc.RootElement.GetProperty("operations")[0]; + JsonElement op = doc.RootElement.GetProperty(DistributedTransactionSerializer.Operations)[0]; - Assert.IsTrue(op.TryGetProperty("resourceBody", out JsonElement resourceBodyElement), + Assert.IsTrue(op.TryGetProperty(DistributedTransactionSerializer.ResourceBody, out JsonElement resourceBodyElement), "resourceBody must be present."); Assert.AreEqual(JsonValueKind.Object, resourceBodyElement.ValueKind, "resourceBody must be a valid JSON object."); @@ -180,14 +180,14 @@ public async Task AllOpTypes_SerializedBody_OperationTypeMatchesOpType() expectedResultCount: 5); using JsonDocument doc = JsonDocument.Parse(capturedJson); - JsonElement ops = doc.RootElement.GetProperty("operations"); + JsonElement ops = doc.RootElement.GetProperty(DistributedTransactionSerializer.Operations); Assert.AreEqual(5, ops.GetArrayLength()); - Assert.AreEqual(OperationType.Create.ToString(), ops[0].GetProperty("operationType").GetString()); - Assert.AreEqual(OperationType.Replace.ToString(), ops[1].GetProperty("operationType").GetString()); - Assert.AreEqual(OperationType.Delete.ToString(), ops[2].GetProperty("operationType").GetString()); - Assert.AreEqual(OperationType.Upsert.ToString(), ops[3].GetProperty("operationType").GetString()); - Assert.AreEqual(OperationType.Patch.ToString(), ops[4].GetProperty("operationType").GetString()); + Assert.AreEqual(OperationType.Create.ToString(), ops[0].GetProperty(DistributedTransactionSerializer.OperationType).GetString()); + Assert.AreEqual(OperationType.Replace.ToString(), ops[1].GetProperty(DistributedTransactionSerializer.OperationType).GetString()); + Assert.AreEqual(OperationType.Delete.ToString(), ops[2].GetProperty(DistributedTransactionSerializer.OperationType).GetString()); + Assert.AreEqual(OperationType.Upsert.ToString(), ops[3].GetProperty(DistributedTransactionSerializer.OperationType).GetString()); + Assert.AreEqual(OperationType.Patch.ToString(), ops[4].GetProperty(DistributedTransactionSerializer.OperationType).GetString()); } [TestMethod] @@ -205,13 +205,13 @@ public async Task AllOpTypes_SerializedBody_ResourceTypeIsAlwaysDocument() expectedResultCount: 5); using JsonDocument doc = JsonDocument.Parse(capturedJson); - JsonElement ops = doc.RootElement.GetProperty("operations"); + JsonElement ops = doc.RootElement.GetProperty(DistributedTransactionSerializer.Operations); for (int i = 0; i < ops.GetArrayLength(); i++) { Assert.AreEqual( ResourceType.Document.ToString(), - ops[i].GetProperty("resourceType").GetString(), + ops[i].GetProperty(DistributedTransactionSerializer.ResourceType).GetString(), $"Operation[{i}] must have resourceType = 'Document'."); } } @@ -228,18 +228,18 @@ public async Task SerializedOperation_AllPresentFields_HaveCorrectJsonValueKinds tx.ReplaceItem(Database, Container, new PartitionKey("pk"), itemId, new TestItem(itemId))); using JsonDocument doc = JsonDocument.Parse(capturedJson); - JsonElement op = doc.RootElement.GetProperty("operations")[0]; - - Assert.AreEqual(JsonValueKind.String, op.GetProperty("databaseName").ValueKind, "'databaseName' must be a JSON string."); - Assert.AreEqual(JsonValueKind.String, op.GetProperty("collectionName").ValueKind, "'collectionName' must be a JSON string."); - Assert.AreEqual(JsonValueKind.String, op.GetProperty("collectionResourceId").ValueKind, "'collectionResourceId' must be a JSON string."); - Assert.AreEqual(JsonValueKind.String, op.GetProperty("databaseResourceId").ValueKind, "'databaseResourceId' must be a JSON string."); - Assert.AreEqual(JsonValueKind.String, op.GetProperty("id").ValueKind, "'id' must be a JSON string."); - Assert.AreEqual(JsonValueKind.Array, op.GetProperty("partitionKey").ValueKind, "'partitionKey' must be a JSON array, not a quoted string."); - Assert.AreEqual(JsonValueKind.Number, op.GetProperty("index").ValueKind, "'index' must be a JSON number, not a quoted string."); - Assert.AreEqual(JsonValueKind.Object, op.GetProperty("resourceBody").ValueKind, "'resourceBody' must be a JSON object."); - Assert.AreEqual(JsonValueKind.String, op.GetProperty("operationType").ValueKind, "'operationType' must be a JSON string."); - Assert.AreEqual(JsonValueKind.String, op.GetProperty("resourceType").ValueKind, "'resourceType' must be a JSON string."); + JsonElement op = doc.RootElement.GetProperty(DistributedTransactionSerializer.Operations)[0]; + + Assert.AreEqual(JsonValueKind.String, op.GetProperty(DistributedTransactionSerializer.DatabaseName).ValueKind, "'databaseName' must be a JSON string."); + Assert.AreEqual(JsonValueKind.String, op.GetProperty(DistributedTransactionSerializer.CollectionName).ValueKind, "'collectionName' must be a JSON string."); + Assert.AreEqual(JsonValueKind.String, op.GetProperty(DistributedTransactionSerializer.CollectionResourceId).ValueKind, "'collectionResourceId' must be a JSON string."); + Assert.AreEqual(JsonValueKind.String, op.GetProperty(DistributedTransactionSerializer.DatabaseResourceId).ValueKind, "'databaseResourceId' must be a JSON string."); + Assert.AreEqual(JsonValueKind.String, op.GetProperty(DistributedTransactionSerializer.Id).ValueKind, "'id' must be a JSON string."); + Assert.AreEqual(JsonValueKind.Array, op.GetProperty(DistributedTransactionSerializer.PartitionKey).ValueKind, "'partitionKey' must be a JSON array, not a quoted string."); + Assert.AreEqual(JsonValueKind.Number, op.GetProperty(DistributedTransactionSerializer.Index).ValueKind, "'index' must be a JSON number, not a quoted string."); + Assert.AreEqual(JsonValueKind.Object, op.GetProperty(DistributedTransactionSerializer.ResourceBody).ValueKind, "'resourceBody' must be a JSON object."); + Assert.AreEqual(JsonValueKind.String, op.GetProperty(DistributedTransactionSerializer.OperationType).ValueKind, "'operationType' must be a JSON string."); + Assert.AreEqual(JsonValueKind.String, op.GetProperty(DistributedTransactionSerializer.ResourceType).ValueKind, "'resourceType' must be a JSON string."); } // Stream operations @@ -255,13 +255,13 @@ public async Task CreateItemStream_SerializedBody_HasResourceBody_AndIdField() tx => tx.CreateItemStream(Database, Container, new PartitionKey("pk"), itemId, stream)); using JsonDocument doc = JsonDocument.Parse(capturedJson); - JsonElement op = doc.RootElement.GetProperty("operations")[0]; + JsonElement op = doc.RootElement.GetProperty(DistributedTransactionSerializer.Operations)[0]; - Assert.IsTrue(op.TryGetProperty("id", out JsonElement idElement), + Assert.IsTrue(op.TryGetProperty(DistributedTransactionSerializer.Id, out JsonElement idElement), "CreateItemStream operation must include an 'id' field."); Assert.AreEqual(itemId, idElement.GetString(), "The 'id' field must match the id passed to CreateItemStream."); - Assert.IsTrue(op.TryGetProperty("resourceBody", out _), + Assert.IsTrue(op.TryGetProperty(DistributedTransactionSerializer.ResourceBody, out _), "CreateItemStream operation must include a 'resourceBody' field."); } @@ -276,11 +276,11 @@ public async Task ReplaceItemStream_SerializedBody_HasIdAndResourceBody() tx => tx.ReplaceItemStream(Database, Container, new PartitionKey("pk"), itemId, stream)); using JsonDocument doc = JsonDocument.Parse(capturedJson); - JsonElement op = doc.RootElement.GetProperty("operations")[0]; + JsonElement op = doc.RootElement.GetProperty(DistributedTransactionSerializer.Operations)[0]; - Assert.IsTrue(op.TryGetProperty("id", out _), + Assert.IsTrue(op.TryGetProperty(DistributedTransactionSerializer.Id, out _), "ReplaceItemStream operation must include an 'id' field."); - Assert.IsTrue(op.TryGetProperty("resourceBody", out _), + Assert.IsTrue(op.TryGetProperty(DistributedTransactionSerializer.ResourceBody, out _), "ReplaceItemStream operation must include a 'resourceBody' field."); } @@ -295,11 +295,11 @@ public async Task PatchItemStream_SerializedBody_HasIdAndResourceBody() tx => tx.PatchItemStream(Database, Container, new PartitionKey("pk"), itemId, stream)); using JsonDocument doc = JsonDocument.Parse(capturedJson); - JsonElement op = doc.RootElement.GetProperty("operations")[0]; + JsonElement op = doc.RootElement.GetProperty(DistributedTransactionSerializer.Operations)[0]; - Assert.IsTrue(op.TryGetProperty("id", out _), + Assert.IsTrue(op.TryGetProperty(DistributedTransactionSerializer.Id, out _), "PatchItemStream operation must include an 'id' field."); - Assert.IsTrue(op.TryGetProperty("resourceBody", out _), + Assert.IsTrue(op.TryGetProperty(DistributedTransactionSerializer.ResourceBody, out _), "PatchItemStream operation must include a 'resourceBody' field."); } @@ -314,13 +314,13 @@ public async Task UpsertItemStream_SerializedBody_HasResourceBody_AndIdField() tx => tx.UpsertItemStream(Database, Container, new PartitionKey("pk"), itemId, stream)); using JsonDocument doc = JsonDocument.Parse(capturedJson); - JsonElement op = doc.RootElement.GetProperty("operations")[0]; + JsonElement op = doc.RootElement.GetProperty(DistributedTransactionSerializer.Operations)[0]; - Assert.IsTrue(op.TryGetProperty("id", out JsonElement idElement), + Assert.IsTrue(op.TryGetProperty(DistributedTransactionSerializer.Id, out JsonElement idElement), "UpsertItemStream operation must include an 'id' field."); Assert.AreEqual(itemId, idElement.GetString(), "The 'id' field must match the id passed to UpsertItemStream."); - Assert.IsTrue(op.TryGetProperty("resourceBody", out _), + Assert.IsTrue(op.TryGetProperty(DistributedTransactionSerializer.ResourceBody, out _), "UpsertItemStream operation must include a 'resourceBody' field."); } @@ -338,9 +338,9 @@ public async Task ReadItem_WithIfNoneMatchEtag_SerializesEtagField() new DistributedTransactionRequestOptions { IfNoneMatchEtag = etag })); using JsonDocument doc = JsonDocument.Parse(capturedJson); - JsonElement op = doc.RootElement.GetProperty("operations")[0]; + JsonElement op = doc.RootElement.GetProperty(DistributedTransactionSerializer.Operations)[0]; - Assert.IsTrue(op.TryGetProperty("etag", out JsonElement etagElement), + Assert.IsTrue(op.TryGetProperty(DistributedTransactionSerializer.ETag, out JsonElement etagElement), "Read operation with IfNoneMatchEtag must include an 'etag' field."); Assert.AreEqual(etag, etagElement.GetString()); } @@ -353,9 +353,9 @@ public async Task ReadItem_WithoutEtag_DoesNotIncludeEtagField() tx.ReadItem(Database, Container, new PartitionKey("pk"), "read-no-etag")); using JsonDocument doc = JsonDocument.Parse(capturedJson); - JsonElement op = doc.RootElement.GetProperty("operations")[0]; + JsonElement op = doc.RootElement.GetProperty(DistributedTransactionSerializer.Operations)[0]; - Assert.IsFalse(op.TryGetProperty("etag", out _), + Assert.IsFalse(op.TryGetProperty(DistributedTransactionSerializer.ETag, out _), "Read operation without etag options must NOT include an 'etag' field."); } @@ -371,9 +371,9 @@ public async Task ReadItem_WithIfMatchEtag_DoesNotSerializeEtagField() new DistributedTransactionRequestOptions { IfMatchEtag = etag })); using JsonDocument doc = JsonDocument.Parse(capturedJson); - JsonElement op = doc.RootElement.GetProperty("operations")[0]; + JsonElement op = doc.RootElement.GetProperty(DistributedTransactionSerializer.Operations)[0]; - Assert.IsFalse(op.TryGetProperty("etag", out _), + Assert.IsFalse(op.TryGetProperty(DistributedTransactionSerializer.ETag, out _), "Read operation must not use IfMatchEtag; only IfNoneMatchEtag is serialized for reads."); } @@ -391,9 +391,9 @@ public async Task ReplaceItem_WithIfMatchEtag_SerializesEtagField() new DistributedTransactionRequestOptions { IfMatchEtag = etag })); using JsonDocument doc = JsonDocument.Parse(capturedJson); - JsonElement op = doc.RootElement.GetProperty("operations")[0]; + JsonElement op = doc.RootElement.GetProperty(DistributedTransactionSerializer.Operations)[0]; - Assert.IsTrue(op.TryGetProperty("etag", out JsonElement etagElement), + Assert.IsTrue(op.TryGetProperty(DistributedTransactionSerializer.ETag, out JsonElement etagElement), "Replace operation with IfMatchEtag must include an 'etag' field."); Assert.AreEqual(etag, etagElement.GetString()); } @@ -410,9 +410,9 @@ public async Task DeleteItem_WithIfMatchEtag_SerializesEtagField() new DistributedTransactionRequestOptions { IfMatchEtag = etag })); using JsonDocument doc = JsonDocument.Parse(capturedJson); - JsonElement op = doc.RootElement.GetProperty("operations")[0]; + JsonElement op = doc.RootElement.GetProperty(DistributedTransactionSerializer.Operations)[0]; - Assert.IsTrue(op.TryGetProperty("etag", out JsonElement etagElement), + Assert.IsTrue(op.TryGetProperty(DistributedTransactionSerializer.ETag, out JsonElement etagElement), "Delete operation with IfMatchEtag must include an 'etag' field."); Assert.AreEqual(etag, etagElement.GetString()); } @@ -430,9 +430,9 @@ public async Task PatchItem_WithIfMatchEtag_SerializesEtagField() new DistributedTransactionRequestOptions { IfMatchEtag = etag })); using JsonDocument doc = JsonDocument.Parse(capturedJson); - JsonElement op = doc.RootElement.GetProperty("operations")[0]; + JsonElement op = doc.RootElement.GetProperty(DistributedTransactionSerializer.Operations)[0]; - Assert.IsTrue(op.TryGetProperty("etag", out JsonElement etagElement), + Assert.IsTrue(op.TryGetProperty(DistributedTransactionSerializer.ETag, out JsonElement etagElement), "Patch operation with IfMatchEtag must include an 'etag' field."); Assert.AreEqual(etag, etagElement.GetString()); } @@ -447,11 +447,11 @@ public async Task Operations_WithoutIfMatchEtag_DoNotIncludeEtagField() expectedResultCount: 2); using JsonDocument doc = JsonDocument.Parse(capturedJson); - JsonElement ops = doc.RootElement.GetProperty("operations"); + JsonElement ops = doc.RootElement.GetProperty(DistributedTransactionSerializer.Operations); for (int i = 0; i < ops.GetArrayLength(); i++) { - Assert.IsFalse(ops[i].TryGetProperty("etag", out _), + Assert.IsFalse(ops[i].TryGetProperty(DistributedTransactionSerializer.ETag, out _), $"Operation[{i}] without IfMatchEtag must NOT include an 'etag' field."); } } @@ -578,8 +578,10 @@ private Mock BuildContextSetup() ContainerProperties containerProps = ContainerProperties.CreateWithResourceId("ccZ1ANCszwk="); containerProps.PartitionKeyPath = "/pk"; - MockDocumentClient documentClient = new MockDocumentClient(); - documentClient.sessionContainer = new SessionContainer("testhost"); + MockDocumentClient documentClient = new MockDocumentClient + { + sessionContainer = new SessionContainer("testhost") + }; Mock contextMock = new Mock();