diff --git a/Microsoft.Azure.Cosmos/src/Batch/BatchAsyncBatcher.cs b/Microsoft.Azure.Cosmos/src/Batch/BatchAsyncBatcher.cs
index 499eab03d3..c0472328ad 100644
--- a/Microsoft.Azure.Cosmos/src/Batch/BatchAsyncBatcher.cs
+++ b/Microsoft.Azure.Cosmos/src/Batch/BatchAsyncBatcher.cs
@@ -157,6 +157,7 @@ public virtual bool TryAdd(ItemBatchOperation operation)
foreach (ItemBatchOperation itemBatchOperation in batchResponse.Operations)
{
BatchOperationResult response = batchResponse[itemBatchOperation.OperationIndex];
+ itemBatchOperation.Context.Diagnostics.AppendDiagnostics(batchResponse.Diagnostics);
if (!response.IsSuccessStatusCode)
{
Documents.ShouldRetryResult shouldRetry = await itemBatchOperation.Context.ShouldRetryAsync(response, cancellationToken);
diff --git a/Microsoft.Azure.Cosmos/src/Batch/BatchOperationResult.cs b/Microsoft.Azure.Cosmos/src/Batch/BatchOperationResult.cs
index fe2730ea92..1dda376966 100644
--- a/Microsoft.Azure.Cosmos/src/Batch/BatchOperationResult.cs
+++ b/Microsoft.Azure.Cosmos/src/Batch/BatchOperationResult.cs
@@ -85,6 +85,11 @@ public virtual bool IsSuccessStatusCode
///
internal virtual SubStatusCodes SubStatusCode { get; set; }
+ ///
+ /// Gets the cosmos diagnostic information for the current request to Azure Cosmos DB service
+ ///
+ internal virtual CosmosDiagnostics Diagnostics { get; set; }
+
internal static Result ReadOperationResult(Memory input, out BatchOperationResult batchOperationResult)
{
RowBuffer row = new RowBuffer(input.Length);
@@ -184,6 +189,7 @@ internal ResponseMessage ToResponseMessage()
responseMessage.Headers.ETag = this.ETag;
responseMessage.Headers.RetryAfter = this.RetryAfter;
responseMessage.Content = this.ResourceStream;
+ responseMessage.Diagnostics = this.Diagnostics;
return responseMessage;
}
}
diff --git a/Microsoft.Azure.Cosmos/src/Batch/BatchResponse.cs b/Microsoft.Azure.Cosmos/src/Batch/BatchResponse.cs
index a031d75c0a..2a5e03e52e 100644
--- a/Microsoft.Azure.Cosmos/src/Batch/BatchResponse.cs
+++ b/Microsoft.Azure.Cosmos/src/Batch/BatchResponse.cs
@@ -36,9 +36,10 @@ internal BatchResponse(
double requestCharge,
TimeSpan? retryAfter,
string activityId,
+ CosmosDiagnostics cosmosDiagnostics,
ServerBatchRequest serverRequest,
CosmosSerializer serializer)
- : this(statusCode, subStatusCode, errorMessage, requestCharge, retryAfter, activityId, serverRequest.Operations, serializer)
+ : this(statusCode, subStatusCode, errorMessage, requestCharge, retryAfter, activityId, cosmosDiagnostics, serverRequest.Operations, serializer)
{
}
@@ -61,6 +62,7 @@ internal BatchResponse(
requestCharge: 0,
retryAfter: null,
activityId: Guid.Empty.ToString(),
+ cosmosDiagnostics: null,
operations: operations,
serializer: null)
{
@@ -80,6 +82,7 @@ private BatchResponse(
double requestCharge,
TimeSpan? retryAfter,
string activityId,
+ CosmosDiagnostics cosmosDiagnostics,
IReadOnlyList operations,
CosmosSerializer serializer)
{
@@ -91,6 +94,7 @@ private BatchResponse(
this.RequestCharge = requestCharge;
this.RetryAfter = retryAfter;
this.ActivityId = activityId;
+ this.Diagnostics = cosmosDiagnostics;
}
///
@@ -140,6 +144,11 @@ public virtual bool IsSuccessStatusCode
///
public virtual int Count => this.results?.Count ?? 0;
+ ///
+ /// Gets the cosmos diagnostic information for the current request to Azure Cosmos DB service
+ ///
+ public virtual CosmosDiagnostics Diagnostics { get; }
+
internal virtual SubStatusCodes SubStatusCode { get; }
internal virtual CosmosSerializer Serializer { get; }
@@ -236,6 +245,7 @@ internal static async Task FromResponseMessageAsync(
responseMessage.Headers.RequestCharge,
responseMessage.Headers.RetryAfter,
responseMessage.Headers.ActivityId,
+ responseMessage.Diagnostics,
serverRequest,
serializer);
}
@@ -249,6 +259,7 @@ internal static async Task FromResponseMessageAsync(
responseMessage.Headers.RequestCharge,
responseMessage.Headers.RetryAfter,
responseMessage.Headers.ActivityId,
+ responseMessage.Diagnostics,
serverRequest,
serializer);
}
@@ -266,6 +277,7 @@ internal static async Task FromResponseMessageAsync(
responseMessage.Headers.RequestCharge,
responseMessage.Headers.RetryAfter,
responseMessage.Headers.ActivityId,
+ responseMessage.Diagnostics,
serverRequest,
serializer);
}
@@ -338,6 +350,7 @@ record =>
responseMessage.Headers.RequestCharge,
responseMessage.Headers.RetryAfter,
responseMessage.Headers.ActivityId,
+ responseMessage.Diagnostics,
serverRequest,
serializer);
diff --git a/Microsoft.Azure.Cosmos/src/Batch/ItemBatchOperationContext.cs b/Microsoft.Azure.Cosmos/src/Batch/ItemBatchOperationContext.cs
index 833729d2a6..18ca705c71 100644
--- a/Microsoft.Azure.Cosmos/src/Batch/ItemBatchOperationContext.cs
+++ b/Microsoft.Azure.Cosmos/src/Batch/ItemBatchOperationContext.cs
@@ -21,6 +21,8 @@ internal class ItemBatchOperationContext : IDisposable
public Task OperationTask => this.taskCompletionSource.Task;
+ public ItemBatchOperationStatistics Diagnostics { get; } = new ItemBatchOperationStatistics();
+
private readonly IDocumentClientRetryPolicy retryPolicy;
private TaskCompletionSource taskCompletionSource = new TaskCompletionSource();
@@ -56,6 +58,8 @@ public void Complete(
{
if (this.AssertBatcher(completer))
{
+ this.Diagnostics.Complete();
+ result.Diagnostics = this.Diagnostics;
this.taskCompletionSource.SetResult(result);
}
diff --git a/Microsoft.Azure.Cosmos/src/Batch/PartitionKeyRangeBatchResponse.cs b/Microsoft.Azure.Cosmos/src/Batch/PartitionKeyRangeBatchResponse.cs
index c2ff0fc1ab..5feb05c498 100644
--- a/Microsoft.Azure.Cosmos/src/Batch/PartitionKeyRangeBatchResponse.cs
+++ b/Microsoft.Azure.Cosmos/src/Batch/PartitionKeyRangeBatchResponse.cs
@@ -17,6 +17,7 @@ internal class PartitionKeyRangeBatchResponse : BatchResponse
{
// Results sorted in the order operations had been added.
private readonly BatchOperationResult[] resultsByOperationIndex;
+ private readonly BatchResponse serverResponse;
private bool isDisposed;
///
@@ -49,11 +50,10 @@ internal PartitionKeyRangeBatchResponse(
{
this.StatusCode = serverResponse.StatusCode;
- this.ServerResponse = serverResponse;
+ this.serverResponse = serverResponse;
this.resultsByOperationIndex = new BatchOperationResult[originalOperationsCount];
StringBuilder errorMessageBuilder = new StringBuilder();
- List activityIds = new List();
List itemBatchOperations = new List();
// We expect number of results == number of operations here
for (int index = 0; index < serverResponse.Operations.Count; index++)
@@ -74,7 +74,6 @@ internal PartitionKeyRangeBatchResponse(
errorMessageBuilder.AppendFormat("{0}; ", serverResponse.ErrorMessage);
}
- this.ActivityId = serverResponse.ActivityId;
this.ErrorMessage = errorMessageBuilder.Length > 2 ? errorMessageBuilder.ToString(0, errorMessageBuilder.Length - 2) : null;
this.Operations = itemBatchOperations;
this.Serializer = serializer;
@@ -83,12 +82,12 @@ internal PartitionKeyRangeBatchResponse(
///
/// Gets the ActivityId that identifies the server request made to execute the batch request.
///
- public override string ActivityId { get; }
+ public override string ActivityId => this.serverResponse.ActivityId;
- internal override CosmosSerializer Serializer { get; }
+ ///
+ public override CosmosDiagnostics Diagnostics => this.serverResponse.Diagnostics;
- // for unit testing only
- internal BatchResponse ServerResponse { get; private set; }
+ internal override CosmosSerializer Serializer { get; }
///
/// Gets the number of operation results.
@@ -148,7 +147,7 @@ protected override void Dispose(bool disposing)
if (disposing && !this.isDisposed)
{
this.isDisposed = true;
- this.ServerResponse?.Dispose();
+ this.serverResponse?.Dispose();
}
base.Dispose(disposing);
diff --git a/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerCore.cs
index 4fbb4d29c5..d426030c80 100644
--- a/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerCore.cs
+++ b/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerCore.cs
@@ -8,7 +8,6 @@ namespace Microsoft.Azure.Cosmos
using System.IO;
using System.Threading;
using System.Threading.Tasks;
- using Microsoft.Azure.Cosmos.Handlers;
using Microsoft.Azure.Cosmos.Routing;
using Microsoft.Azure.Cosmos.Scripts;
using Microsoft.Azure.Documents;
@@ -290,6 +289,11 @@ internal virtual Task GetRoutingMapAsync(CancellationToken
internal virtual BatchAsyncContainerExecutor InitializeBatchExecutorForContainer()
{
+ if (!this.ClientContext.ClientOptions.AllowBulkExecution)
+ {
+ return null;
+ }
+
return new BatchAsyncContainerExecutor(
this,
this.ClientContext,
diff --git a/Microsoft.Azure.Cosmos/src/Resource/Settings/ItemBatchOperationStatistics.cs b/Microsoft.Azure.Cosmos/src/Resource/Settings/ItemBatchOperationStatistics.cs
new file mode 100644
index 0000000000..f747ccad70
--- /dev/null
+++ b/Microsoft.Azure.Cosmos/src/Resource/Settings/ItemBatchOperationStatistics.cs
@@ -0,0 +1,51 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+namespace Microsoft.Azure.Cosmos
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Text;
+
+ ///
+ /// A batch operation might extend multiple requests due to retries.
+ ///
+ internal class ItemBatchOperationStatistics : CosmosDiagnostics
+ {
+ private readonly DateTime created = DateTime.UtcNow;
+ private readonly List cosmosDiagnostics = new List();
+ private DateTime completed;
+
+ public void AppendDiagnostics(CosmosDiagnostics diagnostics)
+ {
+ this.cosmosDiagnostics.Add(diagnostics);
+ }
+
+ public void Complete()
+ {
+ this.completed = DateTime.UtcNow;
+ }
+
+ public override string ToString()
+ {
+ if (this.cosmosDiagnostics.Count == 0)
+ {
+ return string.Empty;
+ }
+
+ StringBuilder statistics = new StringBuilder($"Bulk operation started at {this.created}. ");
+ if (this.completed != null)
+ {
+ statistics.Append($"Completed at {this.completed}. ");
+ }
+
+ foreach (CosmosDiagnostics pointOperationStatistic in this.cosmosDiagnostics)
+ {
+ statistics.AppendLine(pointOperationStatistic.ToString());
+ }
+
+ return statistics.ToString();
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Batch/CosmosItemBulkTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Batch/CosmosItemBulkTests.cs
index e6b4f46d70..3ef76f423d 100644
--- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Batch/CosmosItemBulkTests.cs
+++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Batch/CosmosItemBulkTests.cs
@@ -54,7 +54,7 @@ public async Task CreateItemStream_WithBulk()
Task task = tasks[i];
ResponseMessage result = await task;
Assert.AreEqual(HttpStatusCode.Created, result.StatusCode);
-
+ Assert.IsFalse(string.IsNullOrEmpty(result.Diagnostics.ToString()));
MyDocument document = cosmosDefaultJsonSerializer.FromStream(result.Content);
Assert.AreEqual(i.ToString(), document.id);
}
@@ -75,6 +75,7 @@ public async Task CreateItemAsync_WithBulk()
{
Task> task = tasks[i];
ItemResponse result = await task;
+ Assert.IsFalse(string.IsNullOrEmpty(result.Diagnostics.ToString()));
Assert.AreEqual(HttpStatusCode.Created, result.StatusCode);
}
}
@@ -95,7 +96,7 @@ public async Task UpsertItemStream_WithBulk()
Task task = tasks[i];
ResponseMessage result = await task;
Assert.AreEqual(HttpStatusCode.Created, result.StatusCode);
-
+ Assert.IsFalse(string.IsNullOrEmpty(result.Diagnostics.ToString()));
MyDocument document = cosmosDefaultJsonSerializer.FromStream(result.Content);
Assert.AreEqual(i.ToString(), document.id);
}
@@ -116,6 +117,7 @@ public async Task UpsertItem_WithBulk()
{
Task> task = tasks[i];
ItemResponse result = await task;
+ Assert.IsFalse(string.IsNullOrEmpty(result.Diagnostics.ToString()));
Assert.AreEqual(HttpStatusCode.Created, result.StatusCode);
}
}
@@ -147,6 +149,7 @@ public async Task DeleteItemStream_WithBulk()
{
Task task = deleteTasks[i];
ResponseMessage result = await task;
+ Assert.IsFalse(string.IsNullOrEmpty(result.Diagnostics.ToString()));
Assert.AreEqual(HttpStatusCode.NoContent, result.StatusCode);
}
}
@@ -178,6 +181,7 @@ public async Task DeleteItem_WithBulk()
{
Task> task = deleteTasks[i];
ItemResponse result = await task;
+ Assert.IsFalse(string.IsNullOrEmpty(result.Diagnostics.ToString()));
Assert.AreEqual(HttpStatusCode.NoContent, result.StatusCode);
}
}
@@ -198,7 +202,7 @@ public async Task ReadItemStream_WithBulk()
await Task.WhenAll(tasks);
List> readTasks = new List>();
- // Delete the items
+ // Read the items
foreach (MyDocument createdDocument in createdDocuments)
{
readTasks.Add(ExecuteReadStreamAsync(this.container, createdDocument));
@@ -209,6 +213,7 @@ public async Task ReadItemStream_WithBulk()
{
Task task = readTasks[i];
ResponseMessage result = await task;
+ Assert.IsFalse(string.IsNullOrEmpty(result.Diagnostics.ToString()));
Assert.AreEqual(HttpStatusCode.OK, result.StatusCode);
}
}
@@ -229,7 +234,7 @@ public async Task ReadItem_WithBulk()
await Task.WhenAll(tasks);
List>> readTasks = new List>>();
- // Delete the items
+ // Read the items
foreach (MyDocument createdDocument in createdDocuments)
{
readTasks.Add(ExecuteReadAsync(this.container, createdDocument));
@@ -240,6 +245,7 @@ public async Task ReadItem_WithBulk()
{
Task> task = readTasks[i];
ItemResponse result = await task;
+ Assert.IsFalse(string.IsNullOrEmpty(result.Diagnostics.ToString()));
Assert.AreEqual(HttpStatusCode.OK, result.StatusCode);
}
}
@@ -271,6 +277,7 @@ public async Task ReplaceItemStream_WithBulk()
{
Task task = replaceTasks[i];
ResponseMessage result = await task;
+ Assert.IsFalse(string.IsNullOrEmpty(result.Diagnostics.ToString()));
Assert.AreEqual(HttpStatusCode.OK, result.StatusCode);
}
}
@@ -302,6 +309,7 @@ public async Task ReplaceItem_WithBulk()
{
Task> task = replaceTasks[i];
ItemResponse result = await task;
+ Assert.IsFalse(string.IsNullOrEmpty(result.Diagnostics.ToString()));
Assert.AreEqual(HttpStatusCode.OK, result.StatusCode);
}
}
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 aea5279738..b1c1b57278 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
@@ -59,7 +59,7 @@ private BatchAsyncBatcherExecuteDelegate Executor
cancellationToken: cancellationToken);
BatchResponse batchresponse = await BatchResponse.PopulateFromContentAsync(
- new ResponseMessage(HttpStatusCode.OK) { Content = responseContent },
+ new ResponseMessage(HttpStatusCode.OK) { Content = responseContent, Diagnostics = new PointOperationStatistics(new CosmosClientSideRequestStatistics()) },
batchRequest,
new CosmosJsonDotNetSerializer());
@@ -94,7 +94,7 @@ private BatchAsyncBatcherExecuteDelegate ExecutorWithSplit
serializer: new CosmosJsonDotNetSerializer(),
cancellationToken: cancellationToken);
- ResponseMessage responseMessage = new ResponseMessage(HttpStatusCode.Gone) { Content = responseContent };
+ ResponseMessage responseMessage = new ResponseMessage(HttpStatusCode.Gone) { Content = responseContent, Diagnostics = new PointOperationStatistics(new CosmosClientSideRequestStatistics()) };
responseMessage.Headers.SubStatusCode = SubStatusCodes.PartitionKeyRangeGone;
BatchResponse batchresponse = await BatchResponse.PopulateFromContentAsync(
@@ -238,13 +238,13 @@ public async Task ExceptionsFailOperationsAsync()
public async Task DispatchProcessInOrderAsync()
{
BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(10, 1000, new CosmosJsonDotNetSerializer(), this.Executor, this.Retrier);
- List contexts = new List(10);
+ List operations = new List(10);
for (int i = 0; i < 10; i++)
{
ItemBatchOperation operation = new ItemBatchOperation(OperationType.Create, i, i.ToString());
ItemBatchOperationContext context = new ItemBatchOperationContext(string.Empty);
operation.AttachContext(context);
- contexts.Add(context);
+ operations.Add(operation);
Assert.IsTrue(batchAsyncBatcher.TryAdd(operation));
}
@@ -252,10 +252,14 @@ public async Task DispatchProcessInOrderAsync()
for (int i = 0; i < 10; i++)
{
- ItemBatchOperationContext context = contexts[i];
- Assert.AreEqual(TaskStatus.RanToCompletion, context.OperationTask.Status);
- BatchOperationResult result = await context.OperationTask;
+ ItemBatchOperation operation = operations[i];
+ Assert.AreEqual(TaskStatus.RanToCompletion, operation.Context.OperationTask.Status);
+ BatchOperationResult result = await operation.Context.OperationTask;
Assert.AreEqual(i.ToString(), result.ETag);
+
+ Assert.IsNotNull(operation.Context.Diagnostics);
+ Assert.AreEqual(operation.Context.Diagnostics.ToString(), result.Diagnostics.ToString());
+ Assert.IsFalse(string.IsNullOrEmpty(operation.Context.Diagnostics.ToString()));
}
}
@@ -361,6 +365,10 @@ public async Task RetrierGetsCalledOnSplit()
retryDelegate.Verify(a => a(It.Is(o => o == operation1), It.IsAny()), Times.Once);
retryDelegate.Verify(a => a(It.Is(o => o == operation2), It.IsAny()), Times.Once);
retryDelegate.Verify(a => a(It.IsAny(), It.IsAny()), Times.Exactly(2));
+ Assert.IsNotNull(operation1.Context.Diagnostics);
+ Assert.IsNotNull(operation2.Context.Diagnostics);
+ Assert.IsTrue(!string.IsNullOrEmpty(operation1.Context.Diagnostics.ToString()));
+ Assert.IsTrue(!string.IsNullOrEmpty(operation2.Context.Diagnostics.ToString()));
}
[TestMethod]
diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncContainerExecutorTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncContainerExecutorTests.cs
index 8bb5ae30c0..cfb658af6e 100644
--- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncContainerExecutorTests.cs
+++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncContainerExecutorTests.cs
@@ -73,6 +73,18 @@ public async Task RetryOnSplit()
It.IsAny>(),
It.IsAny()), Times.Exactly(2));
Assert.AreEqual(HttpStatusCode.OK, result.StatusCode);
+ Assert.IsNotNull(result.Diagnostics);
+
+ int diagnosticsLines = 0;
+ string diagnosticsString = result.Diagnostics.ToString();
+ int index = diagnosticsString.IndexOf(Environment.NewLine);
+ while(index > -1)
+ {
+ diagnosticsLines++;
+ index = diagnosticsString.IndexOf(Environment.NewLine, index + 1);
+ }
+
+ Assert.IsTrue(diagnosticsLines > 2);
}
[TestMethod]
@@ -127,6 +139,18 @@ public async Task RetryOn429()
It.IsAny>(),
It.IsAny()), Times.Exactly(2));
Assert.AreEqual(HttpStatusCode.OK, result.StatusCode);
+ Assert.IsNotNull(result.Diagnostics);
+
+ int diagnosticsLines = 0;
+ string diagnosticsString = result.Diagnostics.ToString();
+ int index = diagnosticsString.IndexOf(Environment.NewLine);
+ while (index > -1)
+ {
+ diagnosticsLines++;
+ index = diagnosticsString.IndexOf(Environment.NewLine, index + 1);
+ }
+
+ Assert.IsTrue(diagnosticsLines > 2);
}
[TestMethod]
@@ -205,7 +229,7 @@ private async Task GenerateSplitResponseAsync(ItemBatchOperatio
serializer: new CosmosJsonDotNetSerializer(),
cancellationToken: CancellationToken.None);
- ResponseMessage responseMessage = new ResponseMessage(HttpStatusCode.Gone) { Content = responseContent };
+ ResponseMessage responseMessage = new ResponseMessage(HttpStatusCode.Gone) { Content = responseContent, Diagnostics = new PointOperationStatistics(new CosmosClientSideRequestStatistics()) };
responseMessage.Headers.SubStatusCode = SubStatusCodes.PartitionKeyRangeGone;
return responseMessage;
}
@@ -232,7 +256,7 @@ private async Task Generate429ResponseAsync(ItemBatchOperation
serializer: new CosmosJsonDotNetSerializer(),
cancellationToken: CancellationToken.None);
- ResponseMessage responseMessage = new ResponseMessage((HttpStatusCode)StatusCodes.TooManyRequests) { Content = responseContent };
+ ResponseMessage responseMessage = new ResponseMessage((HttpStatusCode)StatusCodes.TooManyRequests) { Content = responseContent, Diagnostics = new PointOperationStatistics(new CosmosClientSideRequestStatistics()) };
return responseMessage;
}
@@ -258,7 +282,7 @@ private async Task GenerateOkResponseAsync(ItemBatchOperation i
serializer: new CosmosJsonDotNetSerializer(),
cancellationToken: CancellationToken.None);
- ResponseMessage responseMessage = new ResponseMessage(HttpStatusCode.OK) { Content = responseContent };
+ ResponseMessage responseMessage = new ResponseMessage(HttpStatusCode.OK) { Content = responseContent, Diagnostics = new PointOperationStatistics(new CosmosClientSideRequestStatistics()) };
return responseMessage;
}
diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/ItemBatchOperationStatisticsTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/ItemBatchOperationStatisticsTests.cs
new file mode 100644
index 0000000000..1291218c4f
--- /dev/null
+++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/ItemBatchOperationStatisticsTests.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+namespace Microsoft.Azure.Cosmos.Tests
+{
+ using System;
+ using System.Net;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+ [TestClass]
+ public class ItemBatchOperationStatisticsTests
+ {
+ [TestMethod]
+ public void ToString_WhenEmptyReturnEmptyString()
+ {
+ ItemBatchOperationStatistics itemBatchOperationStatistics = new ItemBatchOperationStatistics();
+ Assert.IsTrue(string.IsNullOrEmpty(itemBatchOperationStatistics.ToString()));
+ }
+
+ [TestMethod]
+ public void ToString_ReturnItemsToString()
+ {
+ ItemBatchOperationStatistics itemBatchOperationStatistics = new ItemBatchOperationStatistics();
+
+ CosmosClientSideRequestStatistics cosmosClientSideRequestStatistics1 = new CosmosClientSideRequestStatistics();
+ cosmosClientSideRequestStatistics1.ContactedReplicas.Add(new Uri("https://one.com"));
+ PointOperationStatistics pointOperation1 = new PointOperationStatistics(cosmosClientSideRequestStatistics1);
+
+ CosmosClientSideRequestStatistics cosmosClientSideRequestStatistics2 = new CosmosClientSideRequestStatistics();
+ cosmosClientSideRequestStatistics2.ContactedReplicas.Add(new Uri("https://two.com"));
+ PointOperationStatistics pointOperation2 = new PointOperationStatistics(cosmosClientSideRequestStatistics2);
+
+ itemBatchOperationStatistics.AppendDiagnostics(pointOperation1);
+ itemBatchOperationStatistics.AppendDiagnostics(pointOperation2);
+
+ string toString = itemBatchOperationStatistics.ToString();
+
+ Assert.IsTrue(toString.Contains(pointOperation1.ToString()));
+ Assert.IsTrue(toString.Contains(pointOperation2.ToString()));
+ }
+
+ [TestMethod]
+ public void Complete_AddsCompleteTime()
+ {
+ ItemBatchOperationStatistics itemBatchOperationStatistics = new ItemBatchOperationStatistics();
+
+ CosmosClientSideRequestStatistics cosmosClientSideRequestStatistics1 = new CosmosClientSideRequestStatistics();
+ cosmosClientSideRequestStatistics1.ContactedReplicas.Add(new Uri("https://one.com"));
+ PointOperationStatistics pointOperation1 = new PointOperationStatistics(cosmosClientSideRequestStatistics1);
+
+ CosmosClientSideRequestStatistics cosmosClientSideRequestStatistics2 = new CosmosClientSideRequestStatistics();
+ cosmosClientSideRequestStatistics2.ContactedReplicas.Add(new Uri("https://two.com"));
+ PointOperationStatistics pointOperation2 = new PointOperationStatistics(cosmosClientSideRequestStatistics2);
+
+ itemBatchOperationStatistics.AppendDiagnostics(pointOperation1);
+ itemBatchOperationStatistics.AppendDiagnostics(pointOperation2);
+ itemBatchOperationStatistics.Complete();
+
+ Assert.IsTrue(itemBatchOperationStatistics.ToString().Contains("Completed at"));
+ }
+ }
+}
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 3deb8b54e4..f544256fe9 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
@@ -61,5 +61,43 @@ public async Task StatusCodesAreSetThroughResponseAsync()
PartitionKeyRangeBatchResponse response = new PartitionKeyRangeBatchResponse(arrayOperations.Length, batchresponse, new CosmosJsonDotNetSerializer());
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
+
+ [TestMethod]
+ public async Task DiagnosticsAreSetThroughResponseAsync()
+ {
+ List results = new List();
+ ItemBatchOperation[] arrayOperations = new ItemBatchOperation[1];
+
+ ItemBatchOperation operation = new ItemBatchOperation(OperationType.AddComputeGatewayRequestCharges, 0, "0");
+
+ results.Add(
+ new BatchOperationResult(HttpStatusCode.OK)
+ {
+ ResourceStream = new MemoryStream(new byte[] { 0x41, 0x42 }, index: 0, count: 2, writable: false, publiclyVisible: true),
+ ETag = operation.Id
+ });
+
+ arrayOperations[0] = operation;
+
+ MemoryStream responseContent = await new BatchResponsePayloadWriter(results).GeneratePayloadAsync();
+
+ SinglePartitionKeyServerBatchRequest batchRequest = await SinglePartitionKeyServerBatchRequest.CreateAsync(
+ partitionKey: null,
+ operations: new ArraySegment(arrayOperations),
+ maxBodyLength: 100,
+ maxOperationCount: 1,
+ serializer: new CosmosJsonDotNetSerializer(),
+ cancellationToken: default(CancellationToken));
+
+ CosmosDiagnostics diagnostics = new PointOperationStatistics(new CosmosClientSideRequestStatistics());
+
+ BatchResponse batchresponse = await BatchResponse.PopulateFromContentAsync(
+ new ResponseMessage(HttpStatusCode.OK) { Content = responseContent, Diagnostics = diagnostics },
+ batchRequest,
+ new CosmosJsonDotNetSerializer());
+
+ PartitionKeyRangeBatchResponse response = new PartitionKeyRangeBatchResponse(arrayOperations.Length, batchresponse, new CosmosJsonDotNetSerializer());
+ Assert.AreEqual(diagnostics, response.Diagnostics);
+ }
}
}
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 da594dde21..5c933f51a9 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
@@ -75,7 +75,8 @@ public void ToResponseMessage_MapsProperties()
ResourceStream = new MemoryStream(new byte[] { 0x41, 0x42 }, index: 0, count: 2, writable: false, publiclyVisible: true),
ETag = "1234",
SubStatusCode = SubStatusCodes.CompletingSplit,
- RetryAfter = TimeSpan.FromSeconds(10)
+ RetryAfter = TimeSpan.FromSeconds(10),
+ Diagnostics = new PointOperationStatistics(new CosmosClientSideRequestStatistics())
};
ResponseMessage response = result.ToResponseMessage();
@@ -84,6 +85,7 @@ public void ToResponseMessage_MapsProperties()
Assert.AreEqual(result.SubStatusCode, response.Headers.SubStatusCode);
Assert.AreEqual(result.RetryAfter, response.Headers.RetryAfter);
Assert.AreEqual(result.StatusCode, response.StatusCode);
+ Assert.AreEqual(result.Diagnostics, response.Diagnostics);
}
private async Task ConstainsSplitIsTrueInternal(HttpStatusCode statusCode, SubStatusCodes subStatusCode)
diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientResourceUnitTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientResourceUnitTests.cs
index 97ba44a1dd..f2198540f8 100644
--- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientResourceUnitTests.cs
+++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientResourceUnitTests.cs
@@ -114,5 +114,47 @@ public void ValidateSetItemRequestOptions()
Assert.IsTrue(httpRequest.Headers.TryGetValue(HttpConstants.HttpHeaders.PostTriggerInclude, out string postTriggerHeader));
}
+ [TestMethod]
+ public void InitializeBatchExecutorForContainer_Null_WhenAllowBulk_False()
+ {
+ string databaseId = "db1234";
+ string crId = "cr42";
+
+ CosmosClientContext context = new ClientContextCore(
+ client: null,
+ clientOptions: new CosmosClientOptions(),
+ userJsonSerializer: null,
+ defaultJsonSerializer: null,
+ sqlQuerySpecSerializer: null,
+ cosmosResponseFactory: null,
+ requestHandler: null,
+ documentClient: null);
+
+ DatabaseCore db = new DatabaseCore(context, databaseId);
+ ContainerCore container = new ContainerCore(context, db, crId);
+ Assert.IsNull(container.BatchExecutor);
+ }
+
+ [TestMethod]
+ public void InitializeBatchExecutorForContainer_NotNull_WhenAllowBulk_True()
+ {
+ string databaseId = "db1234";
+ string crId = "cr42";
+
+ CosmosClientContext context = new ClientContextCore(
+ client: null,
+ clientOptions: new CosmosClientOptions() { AllowBulkExecution = true },
+ userJsonSerializer: null,
+ defaultJsonSerializer: null,
+ sqlQuerySpecSerializer: null,
+ cosmosResponseFactory: null,
+ requestHandler: null,
+ documentClient: null);
+
+ DatabaseCore db = new DatabaseCore(context, databaseId);
+ ContainerCore container = new ContainerCore(context, db, crId);
+ Assert.IsNotNull(container.BatchExecutor);
+ }
+
}
}