diff --git a/Microsoft.Azure.Cosmos/src/Batch/BatchAsyncContainerExecutor.cs b/Microsoft.Azure.Cosmos/src/Batch/BatchAsyncContainerExecutor.cs index 1e97716e95..09634c397e 100644 --- a/Microsoft.Azure.Cosmos/src/Batch/BatchAsyncContainerExecutor.cs +++ b/Microsoft.Azure.Cosmos/src/Batch/BatchAsyncContainerExecutor.cs @@ -142,7 +142,7 @@ internal virtual async Task ValidateOperationAsync( Debug.Assert(BatchAsyncContainerExecutor.ValidateOperationEPK(operation, itemRequestOptions)); } - await operation.MaterializeResourceAsync(this.cosmosClientContext.SerializerCore, cancellationToken); + await operation.EncryptAndMaterializeResourceAsync(this.cosmosClientContext.SerializerCore, cancellationToken); } private static IDocumentClientRetryPolicy GetRetryPolicy(RetryOptions retryOptions) @@ -251,7 +251,13 @@ private async Task ExecuteAsync( using (diagnosticsContext.CreateScope("BatchAsyncContainerExecutor.ToResponse")) { - TransactionalBatchResponse serverResponse = await TransactionalBatchResponse.FromResponseMessageAsync(responseMessage, serverRequest, this.cosmosClientContext.SerializerCore).ConfigureAwait(false); + TransactionalBatchResponse serverResponse = await TransactionalBatchResponse.FromResponseMessageAsync( + responseMessage, + serverRequest, + this.cosmosClientContext.SerializerCore, + shouldPromoteOperationStatus: true, + shouldPerformDecryption: false, + cancellationToken).ConfigureAwait(false); return new PartitionKeyRangeBatchExecutionResult(serverRequest.PartitionKeyRangeId, serverRequest.Operations, serverResponse); } diff --git a/Microsoft.Azure.Cosmos/src/Batch/BatchCore.cs b/Microsoft.Azure.Cosmos/src/Batch/BatchCore.cs index 59eb6f6222..d7d245d2cb 100644 --- a/Microsoft.Azure.Cosmos/src/Batch/BatchCore.cs +++ b/Microsoft.Azure.Cosmos/src/Batch/BatchCore.cs @@ -46,7 +46,8 @@ public override TransactionalBatch CreateItem( operationType: OperationType.Create, operationIndex: this.operations.Count, resource: item, - requestOptions: requestOptions)); + requestOptions: requestOptions, + containerCore: this.container)); return this; } @@ -64,7 +65,8 @@ public override TransactionalBatch CreateItemStream( operationType: OperationType.Create, operationIndex: this.operations.Count, resourceStream: streamPayload, - requestOptions: requestOptions)); + requestOptions: requestOptions, + containerCore: this.container)); return this; } @@ -82,7 +84,8 @@ public override TransactionalBatch ReadItem( operationType: OperationType.Read, operationIndex: this.operations.Count, id: id, - requestOptions: requestOptions)); + requestOptions: requestOptions, + containerCore: this.container)); return this; } @@ -100,7 +103,8 @@ public override TransactionalBatch UpsertItem( operationType: OperationType.Upsert, operationIndex: this.operations.Count, resource: item, - requestOptions: requestOptions)); + requestOptions: requestOptions, + containerCore: this.container)); return this; } @@ -118,7 +122,8 @@ public override TransactionalBatch UpsertItemStream( operationType: OperationType.Upsert, operationIndex: this.operations.Count, resourceStream: streamPayload, - requestOptions: requestOptions)); + requestOptions: requestOptions, + containerCore: this.container)); return this; } @@ -143,7 +148,8 @@ public override TransactionalBatch ReplaceItem( operationIndex: this.operations.Count, id: id, resource: item, - requestOptions: requestOptions)); + requestOptions: requestOptions, + containerCore: this.container)); return this; } @@ -168,7 +174,8 @@ public override TransactionalBatch ReplaceItemStream( operationIndex: this.operations.Count, id: id, resourceStream: streamPayload, - requestOptions: requestOptions)); + requestOptions: requestOptions, + containerCore: this.container)); return this; } @@ -186,7 +193,8 @@ public override TransactionalBatch DeleteItem( operationType: OperationType.Delete, operationIndex: this.operations.Count, id: id, - requestOptions: requestOptions)); + requestOptions: requestOptions, + containerCore: this.container)); return this; } @@ -238,7 +246,8 @@ public virtual TransactionalBatch PatchItemStream( operationIndex: this.operations.Count, id: id, resourceStream: patchStream, - requestOptions: requestOptions)); + requestOptions: requestOptions, + containerCore: this.container)); return this; } diff --git a/Microsoft.Azure.Cosmos/src/Batch/BatchExecutor.cs b/Microsoft.Azure.Cosmos/src/Batch/BatchExecutor.cs index 3281a88e69..f46fc5c9ce 100644 --- a/Microsoft.Azure.Cosmos/src/Batch/BatchExecutor.cs +++ b/Microsoft.Azure.Cosmos/src/Batch/BatchExecutor.cs @@ -48,6 +48,11 @@ public async Task ExecuteAsync(CancellationToken can { BatchExecUtils.EnsureValid(this.inputOperations, this.batchOptions); + foreach (ItemBatchOperation operation in this.inputOperations) + { + operation.DiagnosticsContext = this.diagnosticsContext; + } + PartitionKey? serverRequestPartitionKey = this.partitionKey; if (this.batchOptions != null && this.batchOptions.IsEffectivePartitionKeyRouting) { @@ -103,7 +108,10 @@ private async Task ExecuteServerRequestAsync( return await TransactionalBatchResponse.FromResponseMessageAsync( responseMessage, serverRequest, - this.clientContext.SerializerCore); + this.clientContext.SerializerCore, + shouldPromoteOperationStatus: true, + shouldPerformDecryption: true, + cancellationToken); } } } diff --git a/Microsoft.Azure.Cosmos/src/Batch/ItemBatchOperation.cs b/Microsoft.Azure.Cosmos/src/Batch/ItemBatchOperation.cs index d21f7c9def..98ed03b7ad 100644 --- a/Microsoft.Azure.Cosmos/src/Batch/ItemBatchOperation.cs +++ b/Microsoft.Azure.Cosmos/src/Batch/ItemBatchOperation.cs @@ -46,12 +46,14 @@ public ItemBatchOperation( public ItemBatchOperation( OperationType operationType, int operationIndex, + ContainerCore containerCore, string id = null, Stream resourceStream = null, TransactionalBatchItemRequestOptions requestOptions = null) { this.OperationType = operationType; this.OperationIndex = operationIndex; + this.ContainerCore = containerCore; this.Id = id; this.ResourceStream = resourceStream; this.RequestOptions = requestOptions; @@ -70,7 +72,9 @@ public ItemBatchOperation( public int OperationIndex { get; internal set; } - internal CosmosDiagnosticsContext DiagnosticsContext { get; } + internal ContainerCore ContainerCore { get; } + + internal CosmosDiagnosticsContext DiagnosticsContext { get; set; } internal string PartitionKeyJson { get; set; } @@ -308,15 +312,26 @@ internal int GetApproximateSerializedLength() } /// - /// Materializes the operation's resource into a Memory{byte} wrapping a byte array. + /// Encrypts (if encryption options are set) and materializes the operation's resource into a Memory{byte} wrapping a byte array. /// /// Serializer to serialize user provided objects to JSON. /// for cancellation. - internal virtual async Task MaterializeResourceAsync(CosmosSerializerCore serializerCore, CancellationToken cancellationToken) + internal virtual async Task EncryptAndMaterializeResourceAsync(CosmosSerializerCore serializerCore, CancellationToken cancellationToken) { if (this.body.IsEmpty && this.ResourceStream != null) { - this.body = await BatchExecUtils.StreamToMemoryAsync(this.ResourceStream, cancellationToken); + Stream stream = this.ResourceStream; + if (this.ContainerCore != null && this.RequestOptions?.EncryptionOptions != null) + { + stream = await this.ContainerCore.ClientContext.EncryptItemAsync( + stream, + this.RequestOptions.EncryptionOptions, + (DatabaseCore)this.ContainerCore.Database, + this.DiagnosticsContext, + cancellationToken); + } + + this.body = await BatchExecUtils.StreamToMemoryAsync(stream, cancellationToken); } } @@ -372,9 +387,10 @@ public ItemBatchOperation( OperationType operationType, int operationIndex, T resource, + ContainerCore containerCore, string id = null, TransactionalBatchItemRequestOptions requestOptions = null) - : base(operationType, operationIndex, id: id, requestOptions: requestOptions) + : base(operationType, operationIndex, containerCore: containerCore, id: id, requestOptions: requestOptions) { this.Resource = resource; } @@ -386,15 +402,15 @@ public ItemBatchOperation( /// /// Serializer to serialize user provided objects to JSON. /// for cancellation. - internal override Task MaterializeResourceAsync(CosmosSerializerCore serializerCore, CancellationToken cancellationToken) + internal override Task EncryptAndMaterializeResourceAsync(CosmosSerializerCore serializerCore, CancellationToken cancellationToken) { if (this.body.IsEmpty && this.Resource != null) { this.ResourceStream = serializerCore.ToStream(this.Resource); - return base.MaterializeResourceAsync(serializerCore, cancellationToken); + return base.EncryptAndMaterializeResourceAsync(serializerCore, cancellationToken); } - return Task.FromResult(true); + return Task.CompletedTask; } } } \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos/src/Batch/ServerBatchRequest.cs b/Microsoft.Azure.Cosmos/src/Batch/ServerBatchRequest.cs index 52c02ad215..d49104648c 100644 --- a/Microsoft.Azure.Cosmos/src/Batch/ServerBatchRequest.cs +++ b/Microsoft.Azure.Cosmos/src/Batch/ServerBatchRequest.cs @@ -87,7 +87,7 @@ protected async Task> CreateBodyStreamAsync( break; } - await operation.MaterializeResourceAsync(this.serializerCore, cancellationToken); + await operation.EncryptAndMaterializeResourceAsync(this.serializerCore, cancellationToken); materializedCount++; previousOperationIndex = operation.OperationIndex; diff --git a/Microsoft.Azure.Cosmos/src/Batch/TransactionalBatchItemRequestOptions.cs b/Microsoft.Azure.Cosmos/src/Batch/TransactionalBatchItemRequestOptions.cs index c215230835..355aa0f7dc 100644 --- a/Microsoft.Azure.Cosmos/src/Batch/TransactionalBatchItemRequestOptions.cs +++ b/Microsoft.Azure.Cosmos/src/Batch/TransactionalBatchItemRequestOptions.cs @@ -16,9 +16,18 @@ public class TransactionalBatchItemRequestOptions : RequestOptions /// The indexing directive to use with a request. /// /// - /// public IndexingDirective? IndexingDirective { get; set; } + /// + /// Options to encrypt properties of the item. + /// +#if PREVIEW + public +#else + internal +#endif + EncryptionOptions EncryptionOptions { get; set; } + internal static TransactionalBatchItemRequestOptions FromItemRequestOptions(ItemRequestOptions itemRequestOptions) { if (itemRequestOptions == null) diff --git a/Microsoft.Azure.Cosmos/src/Batch/TransactionalBatchResponse.cs b/Microsoft.Azure.Cosmos/src/Batch/TransactionalBatchResponse.cs index 1c7d8d9f24..6ee1ffc172 100644 --- a/Microsoft.Azure.Cosmos/src/Batch/TransactionalBatchResponse.cs +++ b/Microsoft.Azure.Cosmos/src/Batch/TransactionalBatchResponse.cs @@ -9,6 +9,7 @@ namespace Microsoft.Azure.Cosmos using System.Collections.Generic; using System.IO; using System.Net; + using System.Threading; using System.Threading.Tasks; using Microsoft.Azure.Cosmos.Serialization.HybridRow; using Microsoft.Azure.Cosmos.Serialization.HybridRow.RecordIO; @@ -217,7 +218,9 @@ internal static async Task FromResponseMessageAsync( ResponseMessage responseMessage, ServerBatchRequest serverRequest, CosmosSerializerCore serializer, - bool shouldPromoteOperationStatus = true) + bool shouldPromoteOperationStatus, + bool shouldPerformDecryption, + CancellationToken cancellationToken) { using (responseMessage) { @@ -307,6 +310,19 @@ internal static async Task FromResponseMessageAsync( response.CreateAndPopulateResults(serverRequest.Operations, retryAfterMilliseconds); } + else if (shouldPerformDecryption) + { + for (int index = 0; index < serverRequest.Operations.Count; index++) + { + ContainerCore containerCore = serverRequest.Operations[index].ContainerCore; + TransactionalBatchOperationResult result = response.results[index]; + result.ResourceStream = await containerCore.ClientContext.DecryptItemAsync( + result.ResourceStream, + (DatabaseCore)containerCore.Database, + responseMessage.DiagnosticsContext, + cancellationToken); + } + } return response; } diff --git a/Microsoft.Azure.Cosmos/src/Resource/ClientContextCore.cs b/Microsoft.Azure.Cosmos/src/Resource/ClientContextCore.cs index 9f67080e4e..07cc3fd583 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/ClientContextCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/ClientContextCore.cs @@ -5,6 +5,7 @@ namespace Microsoft.Azure.Cosmos { using System; + using System.Diagnostics; using System.IO; using System.Net.Http; using System.Text; @@ -323,6 +324,59 @@ internal override BatchAsyncContainerExecutor GetExecutorForContainer(ContainerC return this.batchExecutorCache.GetExecutorForContainer(container, this); } + internal override async Task EncryptItemAsync( + Stream input, + EncryptionOptions encryptionOptions, + DatabaseCore database, + CosmosDiagnosticsContext diagnosticsContext, + CancellationToken cancellationToken) + { + if (input == null) + { + throw new ArgumentException(ClientResources.InvalidRequestWithEncryptionOptions); + } + + Debug.Assert(encryptionOptions != null); + Debug.Assert(database != null); + Debug.Assert(diagnosticsContext != null); + + using (diagnosticsContext.CreateScope("Encrypt")) + { + return await this.EncryptionProcessor.EncryptAsync( + input, + encryptionOptions, + database, + this.ClientOptions.EncryptionKeyWrapProvider, + diagnosticsContext, + cancellationToken); + } + } + + internal override async Task DecryptItemAsync( + Stream input, + DatabaseCore database, + CosmosDiagnosticsContext diagnosticsContext, + CancellationToken cancellationToken) + { + if (input == null || this.ClientOptions.EncryptionKeyWrapProvider == null) + { + return input; + } + + Debug.Assert(database != null); + Debug.Assert(diagnosticsContext != null); + + using (diagnosticsContext.CreateScope("Decrypt")) + { + return await this.EncryptionProcessor.DecryptAsync( + input, + database, + this.ClientOptions.EncryptionKeyWrapProvider, + diagnosticsContext, + cancellationToken); + } + } + public override void Dispose() { this.Dispose(true); @@ -394,7 +448,7 @@ private bool IsBulkOperationSupported( private static HttpClientHandler CreateHttpClientHandler(CosmosClientOptions clientOptions) { - if (clientOptions == null || (clientOptions.WebProxy == null)) + if (clientOptions == null || clientOptions.WebProxy == null) { return null; } diff --git a/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerCore.Items.cs b/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerCore.Items.cs index 1f09e0c31f..7f0f0506b7 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerCore.Items.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerCore.Items.cs @@ -755,23 +755,14 @@ internal async Task ProcessItemStreamAsync( ContainerCore.ValidatePartitionKey(partitionKey, requestOptions); Uri resourceUri = this.GetResourceUri(requestOptions, operationType, itemId); - if (requestOptions != null && requestOptions.EncryptionOptions != null) + if (requestOptions?.EncryptionOptions != null) { - if (streamPayload == null) - { - throw new ArgumentException(ClientResources.InvalidRequestWithEncryptionOptions); - } - - using (diagnosticsContext.CreateScope("Encrypt")) - { - streamPayload = await this.ClientContext.EncryptionProcessor.EncryptAsync( - streamPayload, - requestOptions.EncryptionOptions, - (DatabaseCore)this.Database, - this.ClientContext.ClientOptions.EncryptionKeyWrapProvider, - diagnosticsContext, - cancellationToken); - } + streamPayload = await this.ClientContext.EncryptItemAsync( + streamPayload, + requestOptions.EncryptionOptions, + (DatabaseCore)this.Database, + diagnosticsContext, + cancellationToken); } ResponseMessage responseMessage = await this.ClientContext.ProcessResourceOperationStreamAsync( @@ -789,15 +780,11 @@ internal async Task ProcessItemStreamAsync( if (responseMessage.Content != null && this.ClientContext.ClientOptions.EncryptionKeyWrapProvider != null) { - using (diagnosticsContext.CreateScope("Decrypt")) - { - responseMessage.Content = await this.ClientContext.EncryptionProcessor.DecryptAsync( - responseMessage.Content, - (DatabaseCore)this.Database, - this.ClientContext.ClientOptions.EncryptionKeyWrapProvider, - diagnosticsContext, - cancellationToken); - } + responseMessage.Content = await this.ClientContext.DecryptItemAsync( + responseMessage.Content, + (DatabaseCore)this.Database, + diagnosticsContext, + cancellationToken); } return responseMessage; diff --git a/Microsoft.Azure.Cosmos/src/Resource/CosmosClientContext.cs b/Microsoft.Azure.Cosmos/src/Resource/CosmosClientContext.cs index 3ffc1feb0e..d40d77026b 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/CosmosClientContext.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/CosmosClientContext.cs @@ -112,6 +112,19 @@ internal abstract Task ProcessResourceOperationAsync( CosmosDiagnosticsContext diagnosticsContext, CancellationToken cancellationToken); + internal abstract Task EncryptItemAsync( + Stream input, + EncryptionOptions encryptionOptions, + DatabaseCore database, + CosmosDiagnosticsContext diagnosticsContext, + CancellationToken cancellationToken); + + internal abstract Task DecryptItemAsync( + Stream input, + DatabaseCore database, + CosmosDiagnosticsContext diagnosticsContext, + CancellationToken cancellationToken); + public abstract void Dispose(); } } \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/EncryptionTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/EncryptionTests.cs index 7b8b371135..d0d491ee89 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/EncryptionTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/EncryptionTests.cs @@ -473,6 +473,62 @@ public async Task EncryptionBulkCrud() await Task.WhenAll(tasks); } + [TestMethod] + public async Task EncryptionTransactionBatchCrud() + { + string partitionKey = "thePK"; + string dek1 = EncryptionTests.dekId; + string dek2 = "dek2Forbatch"; + await EncryptionTests.CreateDekAsync(EncryptionTests.databaseCore, dek2); + + TestDoc doc1ToCreate = TestDoc.Create(partitionKey); + TestDoc doc2ToCreate = TestDoc.Create(partitionKey); + TestDoc doc3ToCreate = TestDoc.Create(partitionKey); + + ItemResponse doc1ToReplaceCreateResponse = await EncryptionTests.CreateItemAsync(EncryptionTests.containerCore, dek1, TestDoc.PathsToEncrypt, partitionKey); + TestDoc doc1ToReplace = doc1ToReplaceCreateResponse.Resource; + doc1ToReplace.NonSensitive = Guid.NewGuid().ToString(); + doc1ToReplace.Sensitive = Guid.NewGuid().ToString(); + + TestDoc doc2ToReplace = await EncryptionTests.CreateItemAsync(EncryptionTests.containerCore, dek2, TestDoc.PathsToEncrypt, partitionKey); + doc2ToReplace.NonSensitive = Guid.NewGuid().ToString(); + doc2ToReplace.Sensitive = Guid.NewGuid().ToString(); + + TestDoc doc1ToUpsert = await EncryptionTests.CreateItemAsync(EncryptionTests.containerCore, dek2, TestDoc.PathsToEncrypt, partitionKey); + doc1ToUpsert.NonSensitive = Guid.NewGuid().ToString(); + doc1ToUpsert.Sensitive = Guid.NewGuid().ToString(); + + TestDoc doc2ToUpsert = await EncryptionTests.CreateItemAsync(EncryptionTests.containerCore, dek1, TestDoc.PathsToEncrypt, partitionKey); + doc2ToUpsert.NonSensitive = Guid.NewGuid().ToString(); + doc2ToUpsert.Sensitive = Guid.NewGuid().ToString(); + + TestDoc docToDelete = await EncryptionTests.CreateItemAsync(EncryptionTests.containerCore, dek1, TestDoc.PathsToEncrypt, partitionKey); + + TransactionalBatchResponse batchResponse = await EncryptionTests.container.CreateTransactionalBatch(new Cosmos.PartitionKey(partitionKey)) + .CreateItem(doc1ToCreate, EncryptionTests.GetBatchItemRequestOptions(containerCore, dek1, TestDoc.PathsToEncrypt)) + .CreateItemStream(doc2ToCreate.ToStream(), EncryptionTests.GetBatchItemRequestOptions(containerCore, dek2, TestDoc.PathsToEncrypt)) + .ReplaceItem(doc1ToReplace.Id, doc1ToReplace, EncryptionTests.GetBatchItemRequestOptions(containerCore, dek2, TestDoc.PathsToEncrypt, doc1ToReplaceCreateResponse.ETag)) + .CreateItem(doc3ToCreate) + .ReplaceItemStream(doc2ToReplace.Id, doc2ToReplace.ToStream(), EncryptionTests.GetBatchItemRequestOptions(containerCore, dek2, TestDoc.PathsToEncrypt)) + .UpsertItem(doc1ToUpsert, EncryptionTests.GetBatchItemRequestOptions(containerCore, dek1, TestDoc.PathsToEncrypt)) + .DeleteItem(docToDelete.Id) + .UpsertItemStream(doc2ToUpsert.ToStream(), EncryptionTests.GetBatchItemRequestOptions(containerCore, dek2, TestDoc.PathsToEncrypt)) + .ExecuteAsync(); + + Assert.AreEqual(HttpStatusCode.OK, batchResponse.StatusCode); + + await EncryptionTests.VerifyItemByReadAsync(EncryptionTests.containerCore, doc1ToCreate); + await EncryptionTests.VerifyItemByReadAsync(EncryptionTests.containerCore, doc2ToCreate); + await EncryptionTests.VerifyItemByReadAsync(EncryptionTests.containerCore, doc3ToCreate); + await EncryptionTests.VerifyItemByReadAsync(EncryptionTests.containerCore, doc1ToReplace); + await EncryptionTests.VerifyItemByReadAsync(EncryptionTests.containerCore, doc2ToReplace); + await EncryptionTests.VerifyItemByReadAsync(EncryptionTests.containerCore, doc1ToUpsert); + await EncryptionTests.VerifyItemByReadAsync(EncryptionTests.containerCore, doc2ToUpsert); + + ResponseMessage readResponseMessage = await container.ReadItemStreamAsync(docToDelete.Id, new PartitionKey(docToDelete.PK)); + Assert.AreEqual(HttpStatusCode.NotFound, readResponseMessage.StatusCode); + } + private static async Task ValidateSprocResultsAsync(ContainerCore containerCore, TestDoc expectedDoc) { string sprocId = Guid.NewGuid().ToString(); @@ -644,9 +700,10 @@ private static async Task> UpsertItemAsync( private static async Task> CreateItemAsync( ContainerCore containerCore, string dekId, - List pathsToEncrypt) + List pathsToEncrypt, + string partitionKey = null) { - TestDoc testDoc = TestDoc.Create(); + TestDoc testDoc = TestDoc.Create(partitionKey); ItemResponse createResponse = await containerCore.CreateItemAsync( testDoc, new PartitionKey(testDoc.PK), @@ -704,6 +761,23 @@ private static ItemRequestOptions GetRequestOptions( }; } + private static TransactionalBatchItemRequestOptions GetBatchItemRequestOptions( + ContainerCore containerCore, + string dekId, + List pathsToEncrypt, + string ifMatchEtag = null) + { + return new TransactionalBatchItemRequestOptions + { + EncryptionOptions = new EncryptionOptions + { + DataEncryptionKey = ((DatabaseCore)containerCore.Database).GetDataEncryptionKey(dekId), + PathsToEncrypt = pathsToEncrypt + }, + IfMatchEtag = ifMatchEtag + }; + } + private static async Task VerifyItemByReadStreamAsync(Container container, TestDoc testDoc) { ResponseMessage readResponseMessage = await container.ReadItemStreamAsync(testDoc.Id, new PartitionKey(testDoc.PK)); @@ -793,16 +867,21 @@ public override int GetHashCode() return hashCode; } - public static TestDoc Create() + public static TestDoc Create(string partitionKey = null) { return new TestDoc() { Id = Guid.NewGuid().ToString(), - PK = Guid.NewGuid().ToString(), + PK = partitionKey ?? Guid.NewGuid().ToString(), NonSensitive = Guid.NewGuid().ToString(), Sensitive = Guid.NewGuid().ToString() }; } + + public Stream ToStream() + { + return TestCommon.SerializerCore.ToStream(this); + } } private class TestKeyWrapProvider : EncryptionKeyWrapProvider diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncBatcherTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncBatcherTests.cs index 7eb7dbdaae..b776d93848 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncBatcherTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncBatcherTests.cs @@ -9,10 +9,8 @@ namespace Microsoft.Azure.Cosmos.Tests using System.IO; using System.Linq; using System.Net; - using System.Net.Http; using System.Threading; using System.Threading.Tasks; - using Microsoft.Azure.Cosmos.Diagnostics; using Microsoft.Azure.Documents; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -28,6 +26,7 @@ private ItemBatchOperation CreateItemBatchOperation(bool withContext = false) ItemBatchOperation operation = new ItemBatchOperation( operationType: OperationType.Create, operationIndex: 0, + partitionKey: Cosmos.PartitionKey.Null, id: string.Empty, resourceStream: new MemoryStream(new byte[] { 0x41, 0x42 }, index: 0, count: 2, writable: false, publiclyVisible: true)); if (withContext) @@ -70,7 +69,10 @@ private BatchAsyncBatcherExecuteDelegate Executor Content = responseContent }, batchRequest, - MockCosmosUtil.Serializer); + MockCosmosUtil.Serializer, + true, + false, + CancellationToken.None); return new PartitionKeyRangeBatchExecutionResult(request.PartitionKeyRangeId, request.Operations, batchresponse); }; @@ -110,7 +112,10 @@ private BatchAsyncBatcherExecuteDelegate ExecutorWithSplit TransactionalBatchResponse batchresponse = await TransactionalBatchResponse.FromResponseMessageAsync( responseMessage, batchRequest, - MockCosmosUtil.Serializer); + MockCosmosUtil.Serializer, + true, + false, + CancellationToken.None); return new PartitionKeyRangeBatchExecutionResult(request.PartitionKeyRangeId, request.Operations, batchresponse); }; @@ -146,7 +151,10 @@ private BatchAsyncBatcherExecuteDelegate ExecutorWithLessResponses TransactionalBatchResponse batchresponse = await TransactionalBatchResponse.FromResponseMessageAsync( new ResponseMessage(HttpStatusCode.OK) { Content = responseContent }, batchRequest, - MockCosmosUtil.Serializer); + MockCosmosUtil.Serializer, + true, + false, + CancellationToken.None); return new PartitionKeyRangeBatchExecutionResult(request.PartitionKeyRangeId, request.Operations, batchresponse); }; @@ -214,7 +222,7 @@ public void HasFixedSize() public async Task HasFixedByteSize() { ItemBatchOperation itemBatchOperation = this.CreateItemBatchOperation(true); - await itemBatchOperation.MaterializeResourceAsync(MockCosmosUtil.Serializer, default(CancellationToken)); + await itemBatchOperation.EncryptAndMaterializeResourceAsync(MockCosmosUtil.Serializer, default(CancellationToken)); // Each operation is 2 bytes BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(3, 4, MockCosmosUtil.Serializer, this.Executor, this.Retrier); Assert.IsTrue(batchAsyncBatcher.TryAdd(itemBatchOperation)); @@ -285,7 +293,7 @@ public async Task DispatchWithLessResponses() List operations = new List(10); for (int i = 0; i < 10; i++) { - ItemBatchOperation operation = new ItemBatchOperation(OperationType.Create, i, i.ToString()); + ItemBatchOperation operation = new ItemBatchOperation(OperationType.Create, i, Cosmos.PartitionKey.Null, i.ToString()); ItemBatchOperationContext context = new ItemBatchOperationContext(string.Empty); operation.AttachContext(context); operations.Add(operation); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncOperationContextTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncOperationContextTests.cs index 28ac02ca63..3c39194076 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncOperationContextTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncOperationContextTests.cs @@ -18,7 +18,7 @@ public class BatchAsyncOperationContextTests public void PartitionKeyRangeIdIsSetOnInitialization() { string expectedPkRangeId = Guid.NewGuid().ToString(); - ItemBatchOperation operation = new ItemBatchOperation(OperationType.Create, 0); + ItemBatchOperation operation = new ItemBatchOperation(OperationType.Create, 0, Cosmos.PartitionKey.Null); ItemBatchOperationContext batchAsyncOperationContext = new ItemBatchOperationContext(expectedPkRangeId); operation.AttachContext(batchAsyncOperationContext); @@ -31,7 +31,7 @@ public void PartitionKeyRangeIdIsSetOnInitialization() [TestMethod] public void TaskIsCreatedOnInitialization() { - ItemBatchOperation operation = new ItemBatchOperation(OperationType.Create, 0); + ItemBatchOperation operation = new ItemBatchOperation(OperationType.Create, 0, Cosmos.PartitionKey.Null); ItemBatchOperationContext batchAsyncOperationContext = new ItemBatchOperationContext(string.Empty); operation.AttachContext(batchAsyncOperationContext); @@ -43,7 +43,7 @@ public void TaskIsCreatedOnInitialization() [TestMethod] public async Task TaskResultIsSetOnCompleteAsync() { - ItemBatchOperation operation = new ItemBatchOperation(OperationType.Create, 0); + ItemBatchOperation operation = new ItemBatchOperation(OperationType.Create, 0, Cosmos.PartitionKey.Null); ItemBatchOperationContext batchAsyncOperationContext = new ItemBatchOperationContext(string.Empty); operation.AttachContext(batchAsyncOperationContext); @@ -59,7 +59,7 @@ public async Task TaskResultIsSetOnCompleteAsync() public async Task ExceptionIsSetOnFailAsync() { Exception failure = new Exception("It failed"); - ItemBatchOperation operation = new ItemBatchOperation(OperationType.Create, 0); + ItemBatchOperation operation = new ItemBatchOperation(OperationType.Create, 0, Cosmos.PartitionKey.Null); ItemBatchOperationContext batchAsyncOperationContext = new ItemBatchOperationContext(string.Empty); operation.AttachContext(batchAsyncOperationContext); @@ -73,7 +73,7 @@ public async Task ExceptionIsSetOnFailAsync() [TestMethod] public void CannotAttachMoreThanOnce() { - ItemBatchOperation operation = new ItemBatchOperation(OperationType.Create, 0); + ItemBatchOperation operation = new ItemBatchOperation(OperationType.Create, 0, Cosmos.PartitionKey.Null); operation.AttachContext(new ItemBatchOperationContext(string.Empty)); Assert.ThrowsException(() => operation.AttachContext(new ItemBatchOperationContext(string.Empty))); } @@ -82,7 +82,7 @@ public void CannotAttachMoreThanOnce() public async Task ShouldRetry_NoPolicy() { TransactionalBatchOperationResult result = new TransactionalBatchOperationResult(HttpStatusCode.OK); - ItemBatchOperation operation = new ItemBatchOperation(OperationType.Create, 0); + ItemBatchOperation operation = new ItemBatchOperation(OperationType.Create, 0, Cosmos.PartitionKey.Null); operation.AttachContext(new ItemBatchOperationContext(string.Empty)); ShouldRetryResult shouldRetryResult = await operation.Context.ShouldRetryAsync(result, default(CancellationToken)); Assert.IsFalse(shouldRetryResult.ShouldRetry); @@ -94,7 +94,7 @@ public async Task ShouldRetry_WithPolicy_OnSuccess() IDocumentClientRetryPolicy retryPolicy = new BulkPartitionKeyRangeGoneRetryPolicy( new ResourceThrottleRetryPolicy(1)); TransactionalBatchOperationResult result = new TransactionalBatchOperationResult(HttpStatusCode.OK); - ItemBatchOperation operation = new ItemBatchOperation(OperationType.Create, 0); + ItemBatchOperation operation = new ItemBatchOperation(OperationType.Create, 0, Cosmos.PartitionKey.Null); operation.AttachContext(new ItemBatchOperationContext(string.Empty, retryPolicy)); ShouldRetryResult shouldRetryResult = await operation.Context.ShouldRetryAsync(result, default(CancellationToken)); Assert.IsFalse(shouldRetryResult.ShouldRetry); @@ -106,7 +106,7 @@ public async Task ShouldRetry_WithPolicy_On429() IDocumentClientRetryPolicy retryPolicy = new BulkPartitionKeyRangeGoneRetryPolicy( new ResourceThrottleRetryPolicy(1)); TransactionalBatchOperationResult result = new TransactionalBatchOperationResult((HttpStatusCode)StatusCodes.TooManyRequests); - ItemBatchOperation operation = new ItemBatchOperation(OperationType.Create, 0); + ItemBatchOperation operation = new ItemBatchOperation(OperationType.Create, 0, Cosmos.PartitionKey.Null); operation.AttachContext(new ItemBatchOperationContext(string.Empty, retryPolicy)); ShouldRetryResult shouldRetryResult = await operation.Context.ShouldRetryAsync(result, default(CancellationToken)); Assert.IsTrue(shouldRetryResult.ShouldRetry); @@ -118,7 +118,7 @@ public async Task ShouldRetry_WithPolicy_OnSplit() IDocumentClientRetryPolicy retryPolicy = new BulkPartitionKeyRangeGoneRetryPolicy( new ResourceThrottleRetryPolicy(1)); TransactionalBatchOperationResult result = new TransactionalBatchOperationResult(HttpStatusCode.Gone) { SubStatusCode = SubStatusCodes.PartitionKeyRangeGone }; - ItemBatchOperation operation = new ItemBatchOperation(OperationType.Create, 0); + ItemBatchOperation operation = new ItemBatchOperation(OperationType.Create, 0, Cosmos.PartitionKey.Null); operation.AttachContext(new ItemBatchOperationContext(string.Empty, retryPolicy)); ShouldRetryResult shouldRetryResult = await operation.Context.ShouldRetryAsync(result, default(CancellationToken)); Assert.IsTrue(shouldRetryResult.ShouldRetry); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncStreamerTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncStreamerTests.cs index 336246bbec..007a758fbc 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncStreamerTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncStreamerTests.cs @@ -20,7 +20,7 @@ public class BatchAsyncStreamerTests private const int MaxBatchByteSize = 100000; private const int defaultMaxDegreeOfConcurrency = 10; private static Exception expectedException = new Exception(); - private ItemBatchOperation ItemBatchOperation = new ItemBatchOperation(OperationType.Create, 0, "0"); + private ItemBatchOperation ItemBatchOperation = new ItemBatchOperation(OperationType.Create, 0, Cosmos.PartitionKey.Null, "0"); private TimerPool TimerPool = new TimerPool(1); private SemaphoreSlim limiter = new SemaphoreSlim(1, defaultMaxDegreeOfConcurrency); @@ -56,7 +56,10 @@ private BatchAsyncBatcherExecuteDelegate Executor TransactionalBatchResponse batchresponse = await TransactionalBatchResponse.FromResponseMessageAsync( new ResponseMessage(HttpStatusCode.OK) { Content = responseContent }, batchRequest, - MockCosmosUtil.Serializer); + MockCosmosUtil.Serializer, + true, + false, + CancellationToken.None); return new PartitionKeyRangeBatchExecutionResult(request.PartitionKeyRangeId, request.Operations, batchresponse); }; @@ -150,7 +153,7 @@ public async Task ValidatesCongestionControlAsync() List> contexts = new List>(100); for (int i = 0; i < 600; i++) { - ItemBatchOperation operation = new ItemBatchOperation(OperationType.Create, i, i.ToString()); + ItemBatchOperation operation = new ItemBatchOperation(OperationType.Create, i, Cosmos.PartitionKey.Null, i.ToString()); ItemBatchOperationContext context = AttachContext(operation); batchAsyncStreamer.Add(operation); contexts.Add(context.OperationTask); @@ -181,7 +184,7 @@ public async Task DispatchesAsync() List> contexts = new List>(10); for (int i = 0; i < 10; i++) { - ItemBatchOperation operation = new ItemBatchOperation(OperationType.Create, i, i.ToString()); + ItemBatchOperation operation = new ItemBatchOperation(OperationType.Create, i, Cosmos.PartitionKey.Null, i.ToString()); ItemBatchOperationContext context = AttachContext(operation); batchAsyncStreamer.Add(operation); contexts.Add(context.OperationTask); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchRequestPayloadReader.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchRequestPayloadReader.cs index 53f05b0741..ed4527cda6 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchRequestPayloadReader.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchRequestPayloadReader.cs @@ -236,6 +236,7 @@ private static Result ReadOperation(ref RowReader reader, int operationIndex, ou operation = new ItemBatchOperation( operationType: operationType, operationIndex: operationIndex, + partitionKey: Cosmos.PartitionKey.Null, // ParsedPartitionKey is used for validation id: id, requestOptions: requestOptions) { diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchSchemaTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchSchemaTests.cs index 6bffe33447..4b0e3ef45d 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchSchemaTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchSchemaTests.cs @@ -23,12 +23,14 @@ public class BatchSchemaTests public async Task BatchRequestSerializationAsync() { const string partitionKey1 = "pk1"; + ContainerCore containerCore = (ContainerInlineCore)MockCosmosUtil.CreateMockCosmosClient().GetDatabase("db").GetContainer("cont"); ItemBatchOperation[] operations = new ItemBatchOperation[] { new ItemBatchOperation( operationType: OperationType.Create, - operationIndex: 0) + operationIndex: 0, + containerCore:containerCore) { ResourceBody = new byte[] { 0x41, 0x42 } }, @@ -36,6 +38,7 @@ public async Task BatchRequestSerializationAsync() id: "id2", operationType: OperationType.Replace, operationIndex: 1, + containerCore:containerCore, requestOptions: new TransactionalBatchItemRequestOptions() { IfMatchEtag = "theCondition" @@ -66,7 +69,8 @@ public async Task BatchRequestSerializationAsync() [Owner("abpai")] public async Task BatchResponseDeserializationAsync() { - List results = new List(); + ContainerCore containerCore = (ContainerInlineCore)MockCosmosUtil.CreateMockCosmosClient().GetDatabase("db").GetContainer("cont"); + List results = new List(); results.Add(new TransactionalBatchOperationResult(HttpStatusCode.Conflict)); @@ -87,15 +91,18 @@ public async Task BatchResponseDeserializationAsync() operations: new ArraySegment( new ItemBatchOperation[] { - new ItemBatchOperation(OperationType.Read, operationIndex: 0, id: "someId"), - new ItemBatchOperation(OperationType.Read, operationIndex: 0, id: "someId") + new ItemBatchOperation(OperationType.Read, operationIndex: 0, id: "someId", containerCore: containerCore), + new ItemBatchOperation(OperationType.Read, operationIndex: 0, id: "someId", containerCore: containerCore) }), serializerCore: MockCosmosUtil.Serializer, cancellationToken: CancellationToken.None); TransactionalBatchResponse batchResponse = await TransactionalBatchResponse.FromResponseMessageAsync( new ResponseMessage((HttpStatusCode)StatusCodes.MultiStatus) { Content = responseContent }, batchRequest, - MockCosmosUtil.Serializer); + MockCosmosUtil.Serializer, + true, + false, + CancellationToken.None); Assert.IsNotNull(batchRequest); Assert.AreEqual(HttpStatusCode.Conflict, batchResponse.StatusCode); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/PartitionKeyBatchResponseTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/PartitionKeyBatchResponseTests.cs index 32cd335851..438097696b 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/PartitionKeyBatchResponseTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/PartitionKeyBatchResponseTests.cs @@ -24,7 +24,7 @@ public async Task StatusCodesAreSetThroughResponseAsync() List results = new List(); ItemBatchOperation[] arrayOperations = new ItemBatchOperation[1]; - ItemBatchOperation operation = new ItemBatchOperation(OperationType.AddComputeGatewayRequestCharges, 0, "0"); + ItemBatchOperation operation = new ItemBatchOperation(OperationType.Read, 0, Cosmos.PartitionKey.Null, "0"); results.Add( new TransactionalBatchOperationResult(HttpStatusCode.OK) @@ -46,7 +46,10 @@ public async Task StatusCodesAreSetThroughResponseAsync() TransactionalBatchResponse batchresponse = await TransactionalBatchResponse.FromResponseMessageAsync( new ResponseMessage(HttpStatusCode.OK) { Content = responseContent }, batchRequest, - MockCosmosUtil.Serializer); + MockCosmosUtil.Serializer, + true, + false, + CancellationToken.None); PartitionKeyRangeBatchResponse response = new PartitionKeyRangeBatchResponse(arrayOperations.Length, batchresponse, MockCosmosUtil.Serializer); Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); @@ -58,7 +61,7 @@ public async Task DiagnosticsAreSetThroughResponseAsync() List results = new List(); ItemBatchOperation[] arrayOperations = new ItemBatchOperation[1]; - ItemBatchOperation operation = new ItemBatchOperation(OperationType.AddComputeGatewayRequestCharges, 0, "0"); + ItemBatchOperation operation = new ItemBatchOperation(OperationType.Read, 0, Cosmos.PartitionKey.Null, "0"); results.Add( new TransactionalBatchOperationResult(HttpStatusCode.OK) @@ -99,7 +102,10 @@ public async Task DiagnosticsAreSetThroughResponseAsync() TransactionalBatchResponse batchresponse = await TransactionalBatchResponse.FromResponseMessageAsync( responseMessage, batchRequest, - MockCosmosUtil.Serializer); + MockCosmosUtil.Serializer, + true, + false, + CancellationToken.None); PartitionKeyRangeBatchResponse response = new PartitionKeyRangeBatchResponse(arrayOperations.Length, batchresponse, MockCosmosUtil.Serializer); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/PartitionKeyRangeBatchExecutionResultTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/PartitionKeyRangeBatchExecutionResultTests.cs index a5a303923b..e5972463a2 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/PartitionKeyRangeBatchExecutionResultTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/PartitionKeyRangeBatchExecutionResultTests.cs @@ -39,7 +39,7 @@ public async Task StatusCodesAreSetThroughResponseAsync() List results = new List(); ItemBatchOperation[] arrayOperations = new ItemBatchOperation[1]; - ItemBatchOperation operation = new ItemBatchOperation(OperationType.Read, 0, "0"); + ItemBatchOperation operation = new ItemBatchOperation(OperationType.Read, 0, Cosmos.PartitionKey.Null, "0"); results.Add( new TransactionalBatchOperationResult(HttpStatusCode.OK) @@ -61,7 +61,10 @@ public async Task StatusCodesAreSetThroughResponseAsync() TransactionalBatchResponse batchresponse = await TransactionalBatchResponse.FromResponseMessageAsync( new ResponseMessage(HttpStatusCode.OK) { Content = responseContent }, batchRequest, - MockCosmosUtil.Serializer); + MockCosmosUtil.Serializer, + true, + false, + CancellationToken.None); PartitionKeyRangeBatchResponse response = new PartitionKeyRangeBatchResponse( arrayOperations.Length, @@ -114,7 +117,7 @@ private async Task ConstainsSplitIsTrueInternal(HttpStatusCode statusCode, List results = new List(); ItemBatchOperation[] arrayOperations = new ItemBatchOperation[1]; - ItemBatchOperation operation = new ItemBatchOperation(OperationType.Read, 0, "0"); + ItemBatchOperation operation = new ItemBatchOperation(OperationType.Read, 0, Cosmos.PartitionKey.Null, "0"); results.Add( new TransactionalBatchOperationResult(HttpStatusCode.OK) @@ -139,7 +142,10 @@ private async Task ConstainsSplitIsTrueInternal(HttpStatusCode statusCode, TransactionalBatchResponse batchresponse = await TransactionalBatchResponse.FromResponseMessageAsync( response, batchRequest, - MockCosmosUtil.Serializer); + MockCosmosUtil.Serializer, + true, + false, + CancellationToken.None); PartitionKeyRangeBatchExecutionResult result = new PartitionKeyRangeBatchExecutionResult("0", arrayOperations, batchresponse); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/PartitionKeyRangeServerBatchRequestTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/PartitionKeyRangeServerBatchRequestTests.cs index 0f90f294ca..bfbbed3ec5 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/PartitionKeyRangeServerBatchRequestTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/PartitionKeyRangeServerBatchRequestTests.cs @@ -18,7 +18,7 @@ public class PartitionKeyRangeServerBatchRequestTests { private static ItemBatchOperation CreateItemBatchOperation(string id = "") { - return new ItemBatchOperation(OperationType.Create, 0, id, new MemoryStream(new byte[] { 0x41, 0x42 }, index: 0, count: 2, writable: false, publiclyVisible: true)); + return new ItemBatchOperation(OperationType.Create, 0, Cosmos.PartitionKey.Null, id, new MemoryStream(new byte[] { 0x41, 0x42 }, index: 0, count: 2, writable: false, publiclyVisible: true)); } [TestMethod] @@ -161,7 +161,7 @@ private static async Task [3.7.0-preview2](https://www.nuget.org/packages/Microsoft.Azure.Cosmos/3.7.1-preview) - 2020-03-30