diff --git a/Directory.Build.props b/Directory.Build.props
index 4bdeecd200..14db28f1fb 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -3,7 +3,7 @@
3.52.0
3.53.0
preview.0
- 3.40.1
+ 3.39.1
1.0.0
beta.0
2.0.5
diff --git a/Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs b/Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs
index 1bc8ed5a80..1d05463702 100644
--- a/Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs
+++ b/Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs
@@ -294,9 +294,9 @@ internal DocumentServiceRequest ToDocumentServiceRequest()
}
serviceRequest.UseStatusCodeForFailures = true;
- serviceRequest.UseStatusCodeFor429 = true;
- serviceRequest.UseStatusCodeFor4041002 = true;
- serviceRequest.UseStatusCodeFor403 = true;
+ serviceRequest.UseStatusCodeFor429 = true;
+ serviceRequest.UseStatusCodeFor4041002 = true;
+ serviceRequest.UseStatusCodeFor403 = true;
serviceRequest.UseStatusCodeForBadRequest = true;
serviceRequest.Properties = this.Properties;
this.DocumentServiceRequest = serviceRequest;
diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs
index 11a4a61f2d..277c7b868b 100644
--- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs
+++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs
@@ -1,81 +1,81 @@
-//------------------------------------------------------------
-// Copyright (c) Microsoft Corporation. All rights reserved.
-//------------------------------------------------------------
-
-namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests
-{
- using System;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Diagnostics;
- using System.Globalization;
- using System.IO;
- using System.Linq;
- using System.Net;
- using System.Net.Http;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
- using Microsoft.Azure.Cosmos.Json;
- using Microsoft.Azure.Cosmos.Query.Core.ExecutionContext;
- using Microsoft.Azure.Cosmos.Query.Core.QueryClient;
- using Microsoft.Azure.Cosmos.Routing;
- using Microsoft.Azure.Cosmos.Tracing;
- using Microsoft.Azure.Documents;
- using Microsoft.Azure.Cosmos;
- using Microsoft.VisualStudio.TestTools.UnitTesting;
- using Newtonsoft.Json;
- using Newtonsoft.Json.Linq;
- using JsonReader = Json.JsonReader;
- using JsonWriter = Json.JsonWriter;
- using PartitionKey = Documents.PartitionKey;
- using static Microsoft.Azure.Cosmos.SDK.EmulatorTests.TransportClientHelper;
- using System.Reflection;
- using System.Text.RegularExpressions;
- using Microsoft.Azure.Cosmos.Diagnostics;
-
- [TestClass]
- public class CosmosItemTests : BaseCosmosClientHelper
- {
- private Container Container = null;
- private ContainerProperties containerSettings = null;
-
- private static readonly string nonPartitionItemId = "fixed-Container-Item";
- private static readonly string undefinedPartitionItemId = "undefined-partition-Item";
-
- [TestInitialize]
- public async Task TestInitialize()
- {
- await base.TestInit(validateSinglePartitionKeyRangeCacheCall: true);
- string PartitionKey = "/pk";
- this.containerSettings = new ContainerProperties(id: Guid.NewGuid().ToString(), partitionKeyPath: PartitionKey);
- ContainerResponse response = await this.database.CreateContainerAsync(
- this.containerSettings,
- throughput: 15000,
- cancellationToken: this.cancellationToken);
- Assert.IsNotNull(response);
- Assert.IsNotNull(response.Container);
- Assert.IsNotNull(response.Resource);
- this.Container = response;
- }
-
- [TestCleanup]
- public async Task Cleanup()
- {
- await base.TestCleanup();
- }
-
- [TestMethod]
- public void ParentResourceTest()
- {
- Assert.AreEqual(this.database, this.Container.Database);
- Assert.AreEqual(this.GetClient(), this.Container.Database.Client);
- }
-
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
+ using System.Diagnostics;
+ using System.Globalization;
+ using System.IO;
+ using System.Linq;
+ using System.Net;
+ using System.Net.Http;
+ using System.Text;
+ using System.Threading;
+ using System.Threading.Tasks;
+ using Microsoft.Azure.Cosmos.Json;
+ using Microsoft.Azure.Cosmos.Query.Core.ExecutionContext;
+ using Microsoft.Azure.Cosmos.Query.Core.QueryClient;
+ using Microsoft.Azure.Cosmos.Routing;
+ using Microsoft.Azure.Cosmos.Tracing;
+ using Microsoft.Azure.Documents;
+ using Microsoft.Azure.Cosmos;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+ using Newtonsoft.Json;
+ using Newtonsoft.Json.Linq;
+ using JsonReader = Json.JsonReader;
+ using JsonWriter = Json.JsonWriter;
+ using PartitionKey = Documents.PartitionKey;
+ using static Microsoft.Azure.Cosmos.SDK.EmulatorTests.TransportClientHelper;
+ using System.Reflection;
+ using System.Text.RegularExpressions;
+ using Microsoft.Azure.Cosmos.Diagnostics;
+
+ [TestClass]
+ public class CosmosItemTests : BaseCosmosClientHelper
+ {
+ private Container Container = null;
+ private ContainerProperties containerSettings = null;
+
+ private static readonly string nonPartitionItemId = "fixed-Container-Item";
+ private static readonly string undefinedPartitionItemId = "undefined-partition-Item";
+
+ [TestInitialize]
+ public async Task TestInitialize()
+ {
+ await base.TestInit(validateSinglePartitionKeyRangeCacheCall: true);
+ string PartitionKey = "/pk";
+ this.containerSettings = new ContainerProperties(id: Guid.NewGuid().ToString(), partitionKeyPath: PartitionKey);
+ ContainerResponse response = await this.database.CreateContainerAsync(
+ this.containerSettings,
+ throughput: 15000,
+ cancellationToken: this.cancellationToken);
+ Assert.IsNotNull(response);
+ Assert.IsNotNull(response.Container);
+ Assert.IsNotNull(response.Resource);
+ this.Container = response;
+ }
+
+ [TestCleanup]
+ public async Task Cleanup()
+ {
+ await base.TestCleanup();
+ }
+
+ [TestMethod]
+ public void ParentResourceTest()
+ {
+ Assert.AreEqual(this.database, this.Container.Database);
+ Assert.AreEqual(this.GetClient(), this.Container.Database.Client);
+ }
+
[TestMethod]
[DataRow(false, DisplayName = "Test scenario when binary encoding is disabled at client level.")]
- [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
- public async Task CreateDropItemWithInvalidIdCharactersTest(bool binaryEncodingEnabledInClient)
+ [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
+ public async Task CreateDropItemWithInvalidIdCharactersTest(bool binaryEncodingEnabledInClient)
{
try
{
@@ -137,12 +137,12 @@ await this.Container.ReadItemAsync(
{
Environment.SetEnvironmentVariable(ConfigurationManager.BinaryEncodingEnabled, null);
}
- }
-
+ }
+
[TestMethod]
[DataRow(false, DisplayName = "Test scenario when binary encoding is disabled at client level.")]
- [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
- public async Task CreateDropItemTest(bool binaryEncodingEnabledInClient)
+ [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
+ public async Task CreateDropItemTest(bool binaryEncodingEnabledInClient)
{
try
{
@@ -187,13 +187,13 @@ public async Task CreateDropItemTest(bool binaryEncodingEnabledInClient)
finally
{
Environment.SetEnvironmentVariable(ConfigurationManager.BinaryEncodingEnabled, null);
- }
- }
-
+ }
+ }
+
[TestMethod]
[DataRow(false, DisplayName = "Test scenario when binary encoding is disabled at client level.")]
- [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
- public async Task ClientConsistencyTestAsync(bool binaryEncodingEnabledInClient)
+ [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
+ public async Task ClientConsistencyTestAsync(bool binaryEncodingEnabledInClient)
{
try
{
@@ -228,13 +228,13 @@ public async Task ClientConsistencyTestAsync(bool binaryEncodingEnabledInClient)
finally
{
Environment.SetEnvironmentVariable(ConfigurationManager.BinaryEncodingEnabled, null);
- }
- }
-
+ }
+ }
+
[TestMethod]
- [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
+ [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
[DataRow(false, DisplayName = "Test scenario when binary encoding is disabled at client level.")]
- public async Task NegativeCreateItemTest(bool binaryEncodingEnabledInClient)
+ public async Task NegativeCreateItemTest(bool binaryEncodingEnabledInClient)
{
try
{
@@ -284,13 +284,13 @@ public async Task NegativeCreateItemTest(bool binaryEncodingEnabledInClient)
finally
{
Environment.SetEnvironmentVariable(ConfigurationManager.BinaryEncodingEnabled, null);
- }
- }
-
+ }
+ }
+
[TestMethod]
- [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
+ [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
[DataRow(false, DisplayName = "Test scenario when binary encoding is disabled at client level.")]
- public async Task NegativeCreateDropItemTest(bool binaryEncodingEnabledInClient)
+ public async Task NegativeCreateDropItemTest(bool binaryEncodingEnabledInClient)
{
try
{
@@ -309,13 +309,13 @@ public async Task NegativeCreateDropItemTest(bool binaryEncodingEnabledInClient)
finally
{
Environment.SetEnvironmentVariable(ConfigurationManager.BinaryEncodingEnabled, null);
- }
- }
-
+ }
+ }
+
[TestMethod]
- [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
- [DataRow(false, DisplayName = "Test scenario when binary encoding is disabled at client level.")]
- public async Task MemoryStreamBufferIsAccessibleOnResponse(bool binaryEncodingEnabledInClient)
+ [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
+ [DataRow(false, DisplayName = "Test scenario when binary encoding is disabled at client level.")]
+ public async Task MemoryStreamBufferIsAccessibleOnResponse(bool binaryEncodingEnabledInClient)
{
try
{
@@ -350,13 +350,13 @@ public async Task MemoryStreamBufferIsAccessibleOnResponse(bool binaryEncodingEn
finally
{
Environment.SetEnvironmentVariable(ConfigurationManager.BinaryEncodingEnabled, null);
- }
- }
-
+ }
+ }
+
[TestMethod]
- [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
- [DataRow(false, DisplayName = "Test scenario when binary encoding is disabled at client level.")]
- public async Task CustomSerilizerTest(bool binaryEncodingEnabledInClient)
+ [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
+ [DataRow(false, DisplayName = "Test scenario when binary encoding is disabled at client level.")]
+ public async Task CustomSerilizerTest(bool binaryEncodingEnabledInClient)
{
try
{
@@ -410,13 +410,13 @@ public async Task CustomSerilizerTest(bool binaryEncodingEnabledInClient)
finally
{
Environment.SetEnvironmentVariable(ConfigurationManager.BinaryEncodingEnabled, null);
- }
- }
-
+ }
+ }
+
[TestMethod]
- [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
- [DataRow(false, DisplayName = "Test scenario when binary encoding is disabled at client level.")]
- public async Task CreateDropItemUndefinedPartitionKeyTest(bool binaryEncodingEnabledInClient)
+ [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
+ [DataRow(false, DisplayName = "Test scenario when binary encoding is disabled at client level.")]
+ public async Task CreateDropItemUndefinedPartitionKeyTest(bool binaryEncodingEnabledInClient)
{
try
{
@@ -443,13 +443,13 @@ public async Task CreateDropItemUndefinedPartitionKeyTest(bool binaryEncodingEna
finally
{
Environment.SetEnvironmentVariable(ConfigurationManager.BinaryEncodingEnabled, null);
- }
- }
-
+ }
+ }
+
[TestMethod]
- [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
- [DataRow(false, DisplayName = "Test scenario when binary encoding is disabled at client level.")]
- public async Task CreateDropItemPartitionKeyNotInTypeTest(bool binaryEncodingEnabledInClient)
+ [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
+ [DataRow(false, DisplayName = "Test scenario when binary encoding is disabled at client level.")]
+ public async Task CreateDropItemPartitionKeyNotInTypeTest(bool binaryEncodingEnabledInClient)
{
try
{
@@ -491,13 +491,13 @@ public async Task CreateDropItemPartitionKeyNotInTypeTest(bool binaryEncodingEna
finally
{
Environment.SetEnvironmentVariable(ConfigurationManager.BinaryEncodingEnabled, null);
- }
- }
-
+ }
+ }
+
[TestMethod]
- [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
- [DataRow(false, DisplayName = "Test scenario when binary encoding is disabled at client level.")]
- public async Task CreateDropItemMultiPartPartitionKeyTest(bool binaryEncodingEnabledInClient)
+ [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
+ [DataRow(false, DisplayName = "Test scenario when binary encoding is disabled at client level.")]
+ public async Task CreateDropItemMultiPartPartitionKeyTest(bool binaryEncodingEnabledInClient)
{
try
{
@@ -547,26 +547,26 @@ public async Task CreateDropItemMultiPartPartitionKeyTest(bool binaryEncodingEna
finally
{
Environment.SetEnvironmentVariable(ConfigurationManager.BinaryEncodingEnabled, null);
- }
- }
-
- [TestMethod]
- public async Task ReadCollectionNotExists()
- {
- string collectionName = Guid.NewGuid().ToString();
- Container testContainer = this.database.GetContainer(collectionName);
- await CosmosItemTests.TestNonePKForNonExistingContainer(testContainer);
-
- // Item -> Container -> Database contract
- string dbName = Guid.NewGuid().ToString();
- testContainer = this.GetClient().GetDatabase(dbName).GetContainer(collectionName);
- await CosmosItemTests.TestNonePKForNonExistingContainer(testContainer);
- }
-
+ }
+ }
+
+ [TestMethod]
+ public async Task ReadCollectionNotExists()
+ {
+ string collectionName = Guid.NewGuid().ToString();
+ Container testContainer = this.database.GetContainer(collectionName);
+ await CosmosItemTests.TestNonePKForNonExistingContainer(testContainer);
+
+ // Item -> Container -> Database contract
+ string dbName = Guid.NewGuid().ToString();
+ testContainer = this.GetClient().GetDatabase(dbName).GetContainer(collectionName);
+ await CosmosItemTests.TestNonePKForNonExistingContainer(testContainer);
+ }
+
[TestMethod]
- [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
- [DataRow(false, DisplayName = "Test scenario when binary encoding is disabled at client level.")]
- public async Task NonPartitionKeyLookupCacheTest(bool binaryEncodingEnabledInClient)
+ [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
+ [DataRow(false, DisplayName = "Test scenario when binary encoding is disabled at client level.")]
+ public async Task NonPartitionKeyLookupCacheTest(bool binaryEncodingEnabledInClient)
{
try
{
@@ -667,7 +667,7 @@ public async Task NonPartitionKeyLookupCacheTest(bool binaryEncodingEnabledInCli
finally
{
Environment.SetEnvironmentVariable(ConfigurationManager.BinaryEncodingEnabled, null);
- }
+ }
}
[TestMethod]
@@ -750,11 +750,11 @@ public async Task HttpRequestVersionIsTwoPointZeroWhenUsingThinClientMode()
}
[TestMethod]
- [DataRow(true, true, DisplayName = "Test scenario when binary encoding is enabled at client level and expected stream response type is binary.")]
- [DataRow(true, false, DisplayName = "Test scenario when binary encoding is enabled at client level and expected stream response type is text.")]
- [DataRow(false, true, DisplayName = "Test scenario when binary encoding is disabled at client level and expected stream response type is binary.")]
- [DataRow(false, false, DisplayName = "Test scenario when binary encoding is disabled at client level and expected stream response type is text.")]
- public async Task CreateDropItemStreamTest(bool binaryEncodingEnabledInClient, bool shouldExpectBinaryOnResponse)
+ [DataRow(true, true, DisplayName = "Test scenario when binary encoding is enabled at client level and expected stream response type is binary.")]
+ [DataRow(true, false, DisplayName = "Test scenario when binary encoding is enabled at client level and expected stream response type is text.")]
+ [DataRow(false, true, DisplayName = "Test scenario when binary encoding is disabled at client level and expected stream response type is binary.")]
+ [DataRow(false, false, DisplayName = "Test scenario when binary encoding is disabled at client level and expected stream response type is text.")]
+ public async Task CreateDropItemStreamTest(bool binaryEncodingEnabledInClient, bool shouldExpectBinaryOnResponse)
{
try
{
@@ -846,7 +846,7 @@ public async Task CreateDropItemStreamTest(bool binaryEncodingEnabledInClient, b
finally
{
Environment.SetEnvironmentVariable(ConfigurationManager.BinaryEncodingEnabled, null);
- }
+ }
}
[TestMethod]
@@ -857,7 +857,7 @@ public async Task CreateDropItemStreamTest(bool binaryEncodingEnabledInClient, b
[DataRow(false, false, DisplayName = "Test scenario when binary encoding is disabled at client level and stream conversation for binary encoding is enabled.")]
public async Task CreateItemStream_WithEnableBinaryResponseOptions_ShouldSkipStreamConversation(
bool binaryEncodingEnabledInClient,
- bool enableStreamPassThrough)
+ bool enableStreamPassThrough)
{
Cosmos.Database database = null;
Container container = null;
@@ -969,22 +969,22 @@ public async Task CreateItemStream_WithEnableBinaryResponseOptions_ShouldSkipStr
{
Environment.SetEnvironmentVariable(ConfigurationManager.BinaryEncodingEnabled, null);
- if (container != null)
- {
- await container.DeleteContainerStreamAsync();
+ if (container != null)
+ {
+ await container.DeleteContainerStreamAsync();
}
if (database != null)
{
await database.DeleteAsync();
}
- }
- }
-
+ }
+ }
+
[TestMethod]
[DataRow(false, DisplayName = "Test scenario when binary encoding is disabled at client level.")]
- [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
- public async Task UpsertItemStreamTest(bool binaryEncodingEnabledInClient)
+ [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
+ public async Task UpsertItemStreamTest(bool binaryEncodingEnabledInClient)
{
try
{
@@ -1029,13 +1029,13 @@ public async Task UpsertItemStreamTest(bool binaryEncodingEnabledInClient)
finally
{
Environment.SetEnvironmentVariable(ConfigurationManager.BinaryEncodingEnabled, null);
- }
- }
-
+ }
+ }
+
[TestMethod]
[DataRow(false, DisplayName = "Test scenario when binary encoding is disabled at client level.")]
- [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
- public async Task UpsertItemTest(bool binaryEncodingEnabledInClient)
+ [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
+ public async Task UpsertItemTest(bool binaryEncodingEnabledInClient)
{
try
{
@@ -1068,13 +1068,13 @@ public async Task UpsertItemTest(bool binaryEncodingEnabledInClient)
finally
{
Environment.SetEnvironmentVariable(ConfigurationManager.BinaryEncodingEnabled, null);
- }
- }
-
+ }
+ }
+
[TestMethod]
[DataRow(false, DisplayName = "Test scenario when binary encoding is disabled at client level.")]
- [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
- public async Task ReplaceItemStreamTest(bool binaryEncodingEnabledInClient)
+ [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
+ public async Task ReplaceItemStreamTest(bool binaryEncodingEnabledInClient)
{
try
{
@@ -1128,63 +1128,63 @@ public async Task ReplaceItemStreamTest(bool binaryEncodingEnabledInClient)
finally
{
Environment.SetEnvironmentVariable(ConfigurationManager.BinaryEncodingEnabled, null);
- }
- }
-
- [DataRow(false)]
- [DataRow(true)]
- [DataTestMethod]
- public async Task ItemStreamIterator(bool useStatelessIterator)
- {
- IList deleteList = await ToDoActivity.CreateRandomItems(this.Container, 3, randomPartitionKey: true);
- HashSet itemIds = deleteList.Select(x => x.id).ToHashSet();
-
- string lastContinuationToken = null;
- QueryRequestOptions requestOptions = new QueryRequestOptions()
- {
- MaxItemCount = 1
- };
-
- FeedIterator feedIterator = this.Container.GetItemQueryStreamIterator(
- continuationToken: lastContinuationToken,
- requestOptions: requestOptions);
-
- while (feedIterator.HasMoreResults)
- {
- if (useStatelessIterator)
- {
- feedIterator = this.Container.GetItemQueryStreamIterator(
- continuationToken: lastContinuationToken,
- requestOptions: requestOptions);
- }
-
- using (ResponseMessage responseMessage =
- await feedIterator.ReadNextAsync(this.cancellationToken))
- {
- lastContinuationToken = responseMessage.Headers.ContinuationToken;
- Assert.AreEqual(responseMessage.ContinuationToken, responseMessage.Headers.ContinuationToken);
- Collection response = TestCommon.SerializerCore.FromStream>(responseMessage.Content).Data;
- foreach (ToDoActivity toDoActivity in response)
- {
- if (itemIds.Contains(toDoActivity.id))
- {
- itemIds.Remove(toDoActivity.id);
- }
- }
-
- Assert.IsNull(responseMessage.Diagnostics.GetQueryMetrics());
- }
-
- }
-
- Assert.IsNull(lastContinuationToken);
- Assert.AreEqual(itemIds.Count, 0);
- }
-
+ }
+ }
+
+ [DataRow(false)]
+ [DataRow(true)]
+ [DataTestMethod]
+ public async Task ItemStreamIterator(bool useStatelessIterator)
+ {
+ IList deleteList = await ToDoActivity.CreateRandomItems(this.Container, 3, randomPartitionKey: true);
+ HashSet itemIds = deleteList.Select(x => x.id).ToHashSet();
+
+ string lastContinuationToken = null;
+ QueryRequestOptions requestOptions = new QueryRequestOptions()
+ {
+ MaxItemCount = 1
+ };
+
+ FeedIterator feedIterator = this.Container.GetItemQueryStreamIterator(
+ continuationToken: lastContinuationToken,
+ requestOptions: requestOptions);
+
+ while (feedIterator.HasMoreResults)
+ {
+ if (useStatelessIterator)
+ {
+ feedIterator = this.Container.GetItemQueryStreamIterator(
+ continuationToken: lastContinuationToken,
+ requestOptions: requestOptions);
+ }
+
+ using (ResponseMessage responseMessage =
+ await feedIterator.ReadNextAsync(this.cancellationToken))
+ {
+ lastContinuationToken = responseMessage.Headers.ContinuationToken;
+ Assert.AreEqual(responseMessage.ContinuationToken, responseMessage.Headers.ContinuationToken);
+ Collection response = TestCommon.SerializerCore.FromStream>(responseMessage.Content).Data;
+ foreach (ToDoActivity toDoActivity in response)
+ {
+ if (itemIds.Contains(toDoActivity.id))
+ {
+ itemIds.Remove(toDoActivity.id);
+ }
+ }
+
+ Assert.IsNull(responseMessage.Diagnostics.GetQueryMetrics());
+ }
+
+ }
+
+ Assert.IsNull(lastContinuationToken);
+ Assert.AreEqual(itemIds.Count, 0);
+ }
+
[TestMethod]
- [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
+ [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
[DataRow(false, DisplayName = "Test scenario when binary encoding is disabled at client level.")]
- public async Task PartitionKeyDeleteTest(bool binaryEncodingEnabledInClient)
+ public async Task PartitionKeyDeleteTest(bool binaryEncodingEnabledInClient)
{
try
{
@@ -1245,13 +1245,13 @@ public async Task PartitionKeyDeleteTest(bool binaryEncodingEnabledInClient)
finally
{
Environment.SetEnvironmentVariable(ConfigurationManager.BinaryEncodingEnabled, null);
- }
- }
-
+ }
+ }
+
[TestMethod]
[DataRow(false, DisplayName = "Test scenario when binary encoding is disabled at client level.")]
- [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
- public async Task PartitionKeyDeleteTestForSubpartitionedContainer(bool binaryEncodingEnabledInClient)
+ [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
+ public async Task PartitionKeyDeleteTestForSubpartitionedContainer(bool binaryEncodingEnabledInClient)
{
try
{
@@ -1336,2276 +1336,2275 @@ public async Task PartitionKeyDeleteTestForSubpartitionedContainer(bool binaryEn
finally
{
Environment.SetEnvironmentVariable(ConfigurationManager.BinaryEncodingEnabled, null);
- }
- }
-
+ }
+ }
+
+ [TestMethod]
+ public async Task ItemCustomSerializerTest()
+ {
+ DateTime createDateTime = DateTime.UtcNow;
+ Dictionary keyValuePairs = new Dictionary()
+ {
+ {"test1", 42 },
+ {"test42", 9001 }
+ };
+
+ dynamic testItem1 = new
+ {
+ id = "ItemCustomSerialzierTest1",
+ cost = (double?)null,
+ totalCost = 98.2789,
+ pk = "MyCustomStatus",
+ taskNum = 4909,
+ createdDateTime = createDateTime,
+ statusCode = HttpStatusCode.Accepted,
+ itemIds = new int[] { 1, 5, 10 },
+ dictionary = keyValuePairs
+ };
+
+ dynamic testItem2 = new
+ {
+ id = "ItemCustomSerialzierTest2",
+ cost = (double?)null,
+ totalCost = 98.2789,
+ pk = "MyCustomStatus",
+ taskNum = 4909,
+ createdDateTime = createDateTime,
+ statusCode = HttpStatusCode.Accepted,
+ itemIds = new int[] { 1, 5, 10 },
+ dictionary = keyValuePairs
+ };
+
+ JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings()
+ {
+ Converters = new List() { new CosmosSerializerHelper.FormatNumbersAsTextConverter() }
+ };
+
+ List queryDefinitions = new List()
+ {
+ new QueryDefinition("select * from t where t.pk = @pk" ).WithParameter("@pk", testItem1.pk),
+ new QueryDefinition("select * from t where t.cost = @cost" ).WithParameter("@cost", testItem1.cost),
+ new QueryDefinition("select * from t where t.taskNum = @taskNum" ).WithParameter("@taskNum", testItem1.taskNum),
+ new QueryDefinition("select * from t where t.totalCost = @totalCost" ).WithParameter("@totalCost", testItem1.totalCost),
+ new QueryDefinition("select * from t where t.createdDateTime = @createdDateTime" ).WithParameter("@createdDateTime", testItem1.createdDateTime),
+ new QueryDefinition("select * from t where t.statusCode = @statusCode" ).WithParameter("@statusCode", testItem1.statusCode),
+ new QueryDefinition("select * from t where t.itemIds = @itemIds" ).WithParameter("@itemIds", testItem1.itemIds),
+ new QueryDefinition("select * from t where t.dictionary = @dictionary" ).WithParameter("@dictionary", testItem1.dictionary),
+ new QueryDefinition("select * from t where t.pk = @pk and t.cost = @cost" )
+ .WithParameter("@pk", testItem1.pk)
+ .WithParameter("@cost", testItem1.cost),
+ };
+
+ int toStreamCount = 0;
+ int fromStreamCount = 0;
+ CosmosSerializerHelper cosmosSerializerHelper = new CosmosSerializerHelper(
+ jsonSerializerSettings,
+ toStreamCallBack: (itemValue) =>
+ {
+ Type itemType = itemValue?.GetType();
+ if (itemValue == null
+ || itemType == typeof(int)
+ || itemType == typeof(double)
+ || itemType == typeof(string)
+ || itemType == typeof(DateTime)
+ || itemType == typeof(HttpStatusCode)
+ || itemType == typeof(int[])
+ || itemType == typeof(Dictionary))
+ {
+ toStreamCount++;
+ }
+ },
+ fromStreamCallback: (item) => fromStreamCount++);
+
+ CosmosClientOptions options = new CosmosClientOptions()
+ {
+ Serializer = cosmosSerializerHelper
+ };
+
+ CosmosClient clientSerializer = TestCommon.CreateCosmosClient(options);
+ Container containerSerializer = clientSerializer.GetContainer(this.database.Id, this.Container.Id);
+
+ try
+ {
+ await containerSerializer.CreateItemAsync(testItem1);
+ await containerSerializer.CreateItemAsync(testItem2);
+ }
+ catch (CosmosException ex) when (ex.StatusCode == HttpStatusCode.Conflict)
+ {
+ // Ignore conflicts since the object already exists
+ }
+
+ foreach (QueryDefinition queryDefinition in queryDefinitions)
+ {
+ toStreamCount = 0;
+ fromStreamCount = 0;
+
+ List allItems = new List();
+ int pageCount = 0;
+ using (FeedIterator feedIterator = containerSerializer.GetItemQueryIterator(
+ queryDefinition: queryDefinition))
+ {
+ while (feedIterator.HasMoreResults)
+ {
+ // Only need once to verify correct serialization of the query definition
+ FeedResponse response = await feedIterator.ReadNextAsync(this.cancellationToken);
+ Assert.AreEqual(response.Count, response.Count());
+ allItems.AddRange(response);
+ pageCount++;
+ }
+ }
+
+ Assert.AreEqual(2, allItems.Count, $"missing query results. Only found: {allItems.Count} items for query:{queryDefinition.ToSqlQuerySpec().QueryText}");
+ foreach (dynamic item in allItems)
+ {
+ Assert.IsFalse(string.Equals(testItem1.id, item.id) || string.Equals(testItem2.id, item.id));
+ Assert.IsTrue(((JObject)item)["totalCost"].Type == JTokenType.String);
+ Assert.IsTrue(((JObject)item)["taskNum"].Type == JTokenType.String);
+ }
+
+ // Each parameter in query spec should be a call to the custom serializer
+ int parameterCount = queryDefinition.ToSqlQuerySpec().Parameters.Count;
+ Assert.AreEqual((parameterCount * pageCount) + parameterCount, toStreamCount, $"missing to stream call. Expected: {(parameterCount * pageCount) + parameterCount}, Actual: {toStreamCount} for query:{queryDefinition.ToSqlQuerySpec().QueryText}");
+ Assert.AreEqual(pageCount, fromStreamCount);
+ }
+ }
+
+ [TestMethod]
+ public async Task QueryStreamValueTest()
+ {
+ DateTime createDateTime = DateTime.UtcNow;
+
+ dynamic testItem1 = new
+ {
+ id = "testItem1",
+ cost = (double?)null,
+ totalCost = 98.2789,
+ pk = "MyCustomStatus",
+ taskNum = 4909,
+ createdDateTime = createDateTime,
+ statusCode = HttpStatusCode.Accepted,
+ itemIds = new int[] { 1, 5, 10 },
+ itemcode = new byte?[5] { 0x16, (byte)'\0', 0x3, null, (byte)'}' },
+ };
+
+ dynamic testItem2 = new
+ {
+ id = "testItem2",
+ cost = (double?)null,
+ totalCost = 98.2789,
+ pk = "MyCustomStatus",
+ taskNum = 4909,
+ createdDateTime = createDateTime,
+ statusCode = HttpStatusCode.Accepted,
+ itemIds = new int[] { 1, 5, 10 },
+ itemcode = new byte?[5] { 0x16, (byte)'\0', 0x3, null, (byte)'}' },
+ };
+
+ //with Custom Serializer.
+ JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings()
+ {
+ Converters = new List() { new CosmosSerializerHelper.FormatNumbersAsTextConverter() }
+ };
+
+ int toStreamCount = 0;
+ int fromStreamCount = 0;
+ CosmosSerializerHelper cosmosSerializerHelper = new CosmosSerializerHelper(
+ jsonSerializerSettings,
+ toStreamCallBack: (itemValue) =>
+ {
+ Type itemType = itemValue?.GetType();
+ if (itemValue == null
+ || itemType == typeof(int)
+ || itemType == typeof(double)
+ || itemType == typeof(string)
+ || itemType == typeof(DateTime)
+ || itemType == typeof(HttpStatusCode)
+ || itemType == typeof(int[])
+ || itemType == typeof(byte))
+ {
+ toStreamCount++;
+ }
+ },
+ fromStreamCallback: (item) => fromStreamCount++);
+
+ CosmosClientOptions options = new CosmosClientOptions()
+ {
+ Serializer = cosmosSerializerHelper
+ };
+
+ CosmosClient clientSerializer = TestCommon.CreateCosmosClient(options);
+ Container containerSerializer = clientSerializer.GetContainer(this.database.Id, this.Container.Id);
+
+ List queryDefinitions = new List()
+ {
+ new QueryDefinition("select * from t where t.pk = @pk" )
+ .WithParameterStream("@pk", cosmosSerializerHelper.ToStream(testItem1.pk)),
+ new QueryDefinition("select * from t where t.cost = @cost" )
+ .WithParameterStream("@cost", cosmosSerializerHelper.ToStream(testItem1.cost)),
+ new QueryDefinition("select * from t where t.taskNum = @taskNum" )
+ .WithParameterStream("@taskNum", cosmosSerializerHelper.ToStream(testItem1.taskNum)),
+ new QueryDefinition("select * from t where t.totalCost = @totalCost" )
+ .WithParameterStream("@totalCost", cosmosSerializerHelper.ToStream(testItem1.totalCost)),
+ new QueryDefinition("select * from t where t.createdDateTime = @createdDateTime" )
+ .WithParameterStream("@createdDateTime", cosmosSerializerHelper.ToStream(testItem1.createdDateTime)),
+ new QueryDefinition("select * from t where t.statusCode = @statusCode" )
+ .WithParameterStream("@statusCode", cosmosSerializerHelper.ToStream(testItem1.statusCode)),
+ new QueryDefinition("select * from t where t.itemIds = @itemIds" )
+ .WithParameterStream("@itemIds", cosmosSerializerHelper.ToStream(testItem1.itemIds)),
+ new QueryDefinition("select * from t where t.itemcode = @itemcode" )
+ .WithParameterStream("@itemcode", cosmosSerializerHelper.ToStream(testItem1.itemcode)),
+ new QueryDefinition("select * from t where t.pk = @pk and t.cost = @cost" )
+ .WithParameterStream("@pk", cosmosSerializerHelper.ToStream(testItem1.pk))
+ .WithParameterStream("@cost", cosmosSerializerHelper.ToStream(testItem1.cost)),
+ };
+
+ try
+ {
+ await containerSerializer.CreateItemAsync(testItem1);
+ await containerSerializer.CreateItemAsync(testItem2);
+ }
+ catch (CosmosException ex) when (ex.StatusCode == HttpStatusCode.Conflict)
+ {
+ // Ignore conflicts since the object already exists
+ }
+
+ foreach (QueryDefinition queryDefinition in queryDefinitions)
+ {
+ toStreamCount = 0;
+ fromStreamCount = 0;
+
+ List allItems = new List();
+ int pageCount = 0;
+ using (FeedIterator feedIterator = containerSerializer.GetItemQueryIterator(
+ queryDefinition: queryDefinition))
+ {
+ while (feedIterator.HasMoreResults)
+ {
+ // Only need once to verify correct serialization of the query definition
+ FeedResponse response = await feedIterator.ReadNextAsync(this.cancellationToken);
+ string diagnosticString = response.Diagnostics.ToString();
+ Assert.IsTrue(diagnosticString.Contains("Query Response Serialization"));
+ Assert.AreEqual(response.Count, response.Count());
+ allItems.AddRange(response);
+ pageCount++;
+ }
+ }
+
+ Assert.AreEqual(2, allItems.Count, $"missing query results. Only found: {allItems.Count} items for query:{queryDefinition.ToSqlQuerySpec().QueryText}");
+
+ // There should be no call to custom serializer since the parameter values are already serialized.
+ Assert.AreEqual(0, toStreamCount, $"missing to stream call. Expected: 0 , Actual: {toStreamCount} for query:{queryDefinition.ToSqlQuerySpec().QueryText}");
+ Assert.AreEqual(pageCount, fromStreamCount);
+ }
+
+ // get result across pages,multiple requests by setting MaxItemCount to 1.
+ foreach (QueryDefinition queryDefinition in queryDefinitions)
+ {
+ toStreamCount = 0;
+ fromStreamCount = 0;
+
+ List allItems = new List();
+ int pageCount = 0;
+ using (FeedIterator feedIterator = containerSerializer.GetItemQueryIterator(
+ queryDefinition: queryDefinition,
+ requestOptions: new QueryRequestOptions { MaxItemCount = 1 }))
+ {
+ while (feedIterator.HasMoreResults)
+ {
+ // Only need once to verify correct serialization of the query definition
+ FeedResponse response = await feedIterator.ReadNextAsync(this.cancellationToken);
+ Assert.AreEqual(response.Count, response.Count());
+ allItems.AddRange(response);
+ pageCount++;
+ }
+ }
+
+ Assert.AreEqual(2, allItems.Count, $"missing query results. Only found: {allItems.Count} items for query:{queryDefinition.ToSqlQuerySpec().QueryText}");
+
+ // There should be no call to custom serializer since the parameter values are already serialized.
+ Assert.AreEqual(0, toStreamCount, $"missing to stream call. Expected: 0 , Actual: {toStreamCount} for query:{queryDefinition.ToSqlQuerySpec().QueryText}");
+ Assert.AreEqual(pageCount, fromStreamCount);
+ }
+
+
+ // Standard Cosmos Serializer Used
+
+ CosmosClient clientStandardSerializer = TestCommon.CreateCosmosClient(useCustomSeralizer: false);
+ Container containerStandardSerializer = clientStandardSerializer.GetContainer(this.database.Id, this.Container.Id);
+
+ testItem1 = ToDoActivity.CreateRandomToDoActivity();
+ testItem1.pk = "myPk";
+ await containerStandardSerializer.CreateItemAsync(testItem1, new Cosmos.PartitionKey(testItem1.pk));
+
+ testItem2 = ToDoActivity.CreateRandomToDoActivity();
+ testItem2.pk = "myPk";
+ await containerStandardSerializer.CreateItemAsync(testItem2, new Cosmos.PartitionKey(testItem2.pk));
+ CosmosSerializer cosmosSerializer = containerStandardSerializer.Database.Client.ClientOptions.Serializer;
+
+ queryDefinitions = new List()
+ {
+ new QueryDefinition("select * from t where t.pk = @pk" )
+ .WithParameterStream("@pk", cosmosSerializer.ToStream(testItem1.pk)),
+ new QueryDefinition("select * from t where t.cost = @cost" )
+ .WithParameterStream("@cost", cosmosSerializer.ToStream(testItem1.cost)),
+ new QueryDefinition("select * from t where t.taskNum = @taskNum" )
+ .WithParameterStream("@taskNum", cosmosSerializer.ToStream(testItem1.taskNum)),
+ new QueryDefinition("select * from t where t.CamelCase = @CamelCase" )
+ .WithParameterStream("@CamelCase", cosmosSerializer.ToStream(testItem1.CamelCase)),
+ new QueryDefinition("select * from t where t.valid = @valid" )
+ .WithParameterStream("@valid", cosmosSerializer.ToStream(testItem1.valid)),
+ new QueryDefinition("select * from t where t.description = @description" )
+ .WithParameterStream("@description", cosmosSerializer.ToStream(testItem1.description)),
+ new QueryDefinition("select * from t where t.pk = @pk and t.cost = @cost" )
+ .WithParameterStream("@pk", cosmosSerializer.ToStream(testItem1.pk))
+ .WithParameterStream("@cost", cosmosSerializer.ToStream(testItem1.cost)),
+ };
+
+ foreach (QueryDefinition queryDefinition in queryDefinitions)
+ {
+ List allItems = new List();
+ int pageCount = 0;
+ using (FeedIterator feedIterator = containerStandardSerializer.GetItemQueryIterator(
+ queryDefinition: queryDefinition))
+ {
+ while (feedIterator.HasMoreResults)
+ {
+ // Only need once to verify correct serialization of the query definition
+ FeedResponse response = await feedIterator.ReadNextAsync(this.cancellationToken);
+ Assert.AreEqual(response.Count, response.Count());
+ allItems.AddRange(response);
+ pageCount++;
+ }
+ }
+
+ Assert.AreEqual(2, allItems.Count, $"missing query results. Only found: {allItems.Count} items for query:{queryDefinition.ToSqlQuerySpec().QueryText}");
+ if (queryDefinition.QueryText.Contains("pk"))
+ {
+ Assert.AreEqual(1, pageCount);
+ }
+ else
+ {
+ Assert.AreEqual(3, pageCount);
+ }
+
+
+
+ IReadOnlyList<(string Name, object Value)> parameters1 = queryDefinition.GetQueryParameters();
+ IReadOnlyList<(string Name, object Value)> parameters2 = queryDefinition.GetQueryParameters();
+
+ Assert.AreSame(parameters1, parameters2);
+ }
+ }
+
+ [TestMethod]
+ public async Task ItemIterator()
+ {
+ IList deleteList = await ToDoActivity.CreateRandomItems(this.Container, 3, randomPartitionKey: true);
+ HashSet itemIds = deleteList.Select(x => x.id).ToHashSet();
+ FeedIterator feedIterator =
+ this.Container.GetItemQueryIterator();
+ while (feedIterator.HasMoreResults)
+ {
+ foreach (ToDoActivity toDoActivity in await feedIterator.ReadNextAsync(this.cancellationToken))
+ {
+ if (itemIds.Contains(toDoActivity.id))
+ {
+ itemIds.Remove(toDoActivity.id);
+ }
+ }
+ }
+
+ Assert.AreEqual(itemIds.Count, 0);
+ }
+
+ [TestMethod]
+ public async Task PerfItemIterator()
+ {
+ IList deleteList = await ToDoActivity.CreateRandomItems(this.Container, 2000, randomPartitionKey: true);
+ HashSet itemIds = deleteList.Select(x => x.id).ToHashSet();
+
+ FeedIterator feedIterator =
+ this.Container.GetItemQueryIterator();
+ while (feedIterator.HasMoreResults)
+ {
+ foreach (ToDoActivity toDoActivity in await feedIterator.ReadNextAsync(this.cancellationToken))
+ {
+ if (itemIds.Contains(toDoActivity.id))
+ {
+ itemIds.Remove(toDoActivity.id);
+ }
+ }
+ }
+
+ Assert.AreEqual(itemIds.Count, 0);
+ }
+
+
+ [DataRow(1, 1)]
+ [DataRow(5, 5)]
+ [DataRow(6, 2)]
+ [DataTestMethod]
+ public async Task QuerySinglePartitionItemStreamTest(int perPKItemCount, int maxItemCount)
+ {
+ IList deleteList = deleteList = await ToDoActivity.CreateRandomItems(this.Container, pkCount: 3, perPKItemCount: perPKItemCount, randomPartitionKey: true);
+ ToDoActivity find = deleteList.First();
+
+ QueryDefinition sql = new QueryDefinition("select * from r where r.pk = @pk").WithParameter("@pk", find.pk);
+
+ int iterationCount = 0;
+ int totalReadItem = 0;
+ int expectedIterationCount = perPKItemCount / maxItemCount;
+ string lastContinuationToken = null;
+
+ do
+ {
+ iterationCount++;
+ FeedIterator feedIterator = this.Container.GetItemQueryStreamIterator(
+ sql,
+ continuationToken: lastContinuationToken,
+ requestOptions: new QueryRequestOptions()
+ {
+ MaxItemCount = maxItemCount,
+ MaxConcurrency = 1,
+ PartitionKey = new Cosmos.PartitionKey(find.pk),
+ });
+
+ ResponseMessage response = await feedIterator.ReadNextAsync();
+ lastContinuationToken = response.Headers.ContinuationToken;
+ Assert.AreEqual(response.ContinuationToken, response.Headers.ContinuationToken);
+
+ System.Diagnostics.Trace.TraceInformation($"ContinuationToken: {lastContinuationToken}");
+ Newtonsoft.Json.JsonSerializer serializer = new Newtonsoft.Json.JsonSerializer();
+
+ ServerSideCumulativeMetrics metrics = response.Diagnostics.GetQueryMetrics();
+ Assert.IsTrue(metrics.PartitionedMetrics.Count > 0);
+ Assert.IsTrue(metrics.PartitionedMetrics[0].RequestCharge > 0);
+ Assert.IsTrue(metrics.CumulativeMetrics.TotalTime > TimeSpan.Zero);
+ Assert.IsTrue(metrics.CumulativeMetrics.QueryPreparationTime > TimeSpan.Zero);
+ Assert.IsTrue(metrics.TotalRequestCharge > 0);
+
+ if (metrics.CumulativeMetrics.RetrievedDocumentCount >= 1)
+ {
+ Assert.IsTrue(metrics.CumulativeMetrics.RetrievedDocumentSize > 0);
+ Assert.IsTrue(metrics.CumulativeMetrics.DocumentLoadTime > TimeSpan.Zero);
+ Assert.IsTrue(metrics.CumulativeMetrics.RuntimeExecutionTime > TimeSpan.Zero);
+ }
+ else
+ {
+ Assert.AreEqual(0, metrics.CumulativeMetrics.RetrievedDocumentSize);
+ }
+
+ using (StreamReader sr = new StreamReader(response.Content))
+ using (JsonTextReader jtr = new JsonTextReader(sr))
+ {
+ ToDoActivity[] results = serializer.Deserialize>(jtr).Data.ToArray();
+ ToDoActivity[] readTodoActivities = results.OrderBy(e => e.id)
+ .ToArray();
+
+ ToDoActivity[] expectedTodoActivities = deleteList
+ .Where(e => e.pk == find.pk)
+ .Where(e => readTodoActivities.Any(e1 => e1.id == e.id))
+ .OrderBy(e => e.id)
+ .ToArray();
+
+ totalReadItem += expectedTodoActivities.Length;
+ string expectedSerialized = JsonConvert.SerializeObject(expectedTodoActivities);
+ string readSerialized = JsonConvert.SerializeObject(readTodoActivities);
+ System.Diagnostics.Trace.TraceInformation($"Expected: {Environment.NewLine} {expectedSerialized}");
+ System.Diagnostics.Trace.TraceInformation($"Read: {Environment.NewLine} {readSerialized}");
+
+ int count = results.Length;
+ Assert.AreEqual(maxItemCount, count);
+
+ Assert.AreEqual(expectedSerialized, readSerialized);
+
+ Assert.AreEqual(maxItemCount, expectedTodoActivities.Length);
+ }
+ }
+ while (lastContinuationToken != null);
+
+ Assert.AreEqual(expectedIterationCount, iterationCount);
+ Assert.AreEqual(perPKItemCount, totalReadItem);
+ }
+
+ ///
+ /// Validate multiple partition query
+ ///
+ [TestMethod]
+ public async Task ItemMultiplePartitionQuery()
+ {
+ IList itemList = await ToDoActivity.CreateRandomItems(this.Container, 3, randomPartitionKey: true);
+
+ ToDoActivity find = itemList.First();
+ QueryDefinition sql = new QueryDefinition("select * from toDoActivity t where t.id = '" + find.id + "'");
+
+ QueryRequestOptions requestOptions = new QueryRequestOptions()
+ {
+ MaxItemCount = 1,
+ MaxConcurrency = -1,
+ };
+
+ FeedIterator feedIterator = this.Container.GetItemQueryIterator(
+ sql,
+ requestOptions: requestOptions);
+
+ bool found = false;
+ while (feedIterator.HasMoreResults)
+ {
+ FeedResponse iter = await feedIterator.ReadNextAsync();
+ Assert.IsTrue(iter.Count() <= 1);
+ if (iter.Count() == 1)
+ {
+ found = true;
+ ToDoActivity response = iter.First();
+ Assert.AreEqual(find.id, response.id);
+ }
+
+ ServerSideCumulativeMetrics metrics = iter.Diagnostics.GetQueryMetrics();
+
+ if (metrics != null)
+ {
+ // This assumes that we are using parallel prefetch to hit multiple partitions concurrently
+ Assert.IsTrue(metrics.PartitionedMetrics.Count == 3);
+ Assert.IsTrue(metrics.CumulativeMetrics.TotalTime > TimeSpan.Zero);
+ Assert.IsTrue(metrics.CumulativeMetrics.QueryPreparationTime > TimeSpan.Zero);
+ Assert.IsTrue(metrics.TotalRequestCharge > 0);
+
+ foreach (ServerSidePartitionedMetrics partitionedMetrics in metrics.PartitionedMetrics)
+ {
+ Assert.IsNotNull(partitionedMetrics);
+ Assert.IsNotNull(partitionedMetrics.FeedRange);
+ Assert.IsNotNull(partitionedMetrics.PartitionKeyRangeId);
+ Assert.IsTrue(partitionedMetrics.RequestCharge > 0);
+ }
+
+ if (metrics.CumulativeMetrics.RetrievedDocumentCount >= 1)
+ {
+ Assert.IsTrue(metrics.CumulativeMetrics.RetrievedDocumentSize > 0);
+ Assert.IsTrue(metrics.CumulativeMetrics.DocumentLoadTime > TimeSpan.Zero);
+ Assert.IsTrue(metrics.CumulativeMetrics.RuntimeExecutionTime > TimeSpan.Zero);
+ }
+ else
+ {
+ Assert.AreEqual(0, metrics.CumulativeMetrics.RetrievedDocumentSize);
+ }
+ }
+ else
+ {
+ string diag = iter.Diagnostics.ToString();
+ Assert.IsNotNull(diag);
+ }
+ }
+
+ Assert.IsTrue(found);
+ }
+
+ ///
+ /// Validate single partition query using gateway mode.
+ ///
+ [TestMethod]
+ public async Task ItemSinglePartitionQueryGateway()
+ {
+ ContainerResponse containerResponse = await this.database.CreateContainerAsync(
+ new ContainerProperties(id: Guid.NewGuid().ToString(), partitionKeyPath: "/pk"));
+
+ Container createdContainer = (ContainerInlineCore)containerResponse;
+ CosmosClient client1 = TestCommon.CreateCosmosClient(useGateway: true);
+
+ Container container = client1.GetContainer(this.database.Id, createdContainer.Id);
+
+ string findId = "id2002";
+ ToDoActivity item = ToDoActivity.CreateRandomToDoActivity("pk2002", findId);
+ await container.CreateItemAsync(item);
+
+ QueryDefinition sql = new QueryDefinition("select * from toDoActivity t where t.id = '" + findId + "'");
+
+ QueryRequestOptions requestOptions = new QueryRequestOptions()
+ {
+ MaxBufferedItemCount = 10,
+ ResponseContinuationTokenLimitInKb = 500,
+ MaxItemCount = 1,
+ MaxConcurrency = 1,
+ };
+
+ FeedIterator feedIterator = container.GetItemQueryIterator(
+ sql,
+ requestOptions: requestOptions);
+
+ bool found = false;
+ while (feedIterator.HasMoreResults)
+ {
+ FeedResponse iter = await feedIterator.ReadNextAsync();
+ Assert.IsTrue(iter.Count() <= 1);
+ if (iter.Count() == 1)
+ {
+ found = true;
+ ToDoActivity response = iter.First();
+ Assert.AreEqual(findId, response.id);
+ }
+
+ ServerSideCumulativeMetrics metrics = iter.Diagnostics.GetQueryMetrics();
+
+ if (metrics != null)
+ {
+ Assert.IsTrue(metrics.PartitionedMetrics.Count == 1);
+ Assert.IsTrue(metrics.CumulativeMetrics.TotalTime > TimeSpan.Zero);
+ Assert.IsTrue(metrics.CumulativeMetrics.QueryPreparationTime > TimeSpan.Zero);
+ Assert.IsTrue(metrics.TotalRequestCharge > 0);
+
+ foreach (ServerSidePartitionedMetrics partitionedMetrics in metrics.PartitionedMetrics)
+ {
+ Assert.IsNotNull(partitionedMetrics);
+ Assert.IsNotNull(partitionedMetrics.FeedRange);
+ Assert.IsNull(partitionedMetrics.PartitionKeyRangeId);
+ Assert.IsTrue(partitionedMetrics.RequestCharge > 0);
+ }
+
+ if (metrics.CumulativeMetrics.RetrievedDocumentCount >= 1)
+ {
+ Assert.IsTrue(metrics.CumulativeMetrics.RetrievedDocumentSize > 0);
+ Assert.IsTrue(metrics.CumulativeMetrics.DocumentLoadTime > TimeSpan.Zero);
+ Assert.IsTrue(metrics.CumulativeMetrics.RuntimeExecutionTime > TimeSpan.Zero);
+ }
+ else
+ {
+ Assert.AreEqual(0, metrics.CumulativeMetrics.RetrievedDocumentSize);
+ }
+ }
+ }
+
+ Assert.IsTrue(found);
+ }
+
+ ///
+ /// Validate multiple partition query
+ ///
+ [TestMethod]
+ public async Task ItemMultiplePartitionOrderByQueryStream()
+ {
+ CultureInfo defaultCultureInfo = System.Threading.Thread.CurrentThread.CurrentCulture;
+
+ CultureInfo[] cultureInfoList = new CultureInfo[]
+ {
+ defaultCultureInfo,
+ System.Globalization.CultureInfo.GetCultureInfo("fr-FR")
+ };
+
+ IList deleteList = await ToDoActivity.CreateRandomItems(
+ this.Container,
+ 300,
+ randomPartitionKey: true,
+ randomTaskNumber: true);
+
+ try
+ {
+ foreach (CultureInfo cultureInfo in cultureInfoList)
+ {
+ System.Threading.Thread.CurrentThread.CurrentCulture = cultureInfo;
+
+ QueryDefinition sql = new QueryDefinition("SELECT * FROM toDoActivity t ORDER BY t.taskNum ");
+
+ QueryRequestOptions requestOptions = new QueryRequestOptions()
+ {
+ MaxBufferedItemCount = 10,
+ ResponseContinuationTokenLimitInKb = 500,
+ MaxConcurrency = 5,
+ MaxItemCount = 1,
+ };
+
+ List resultList = new List();
+ double totalRequstCharge = 0;
+ FeedIterator feedIterator = this.Container.GetItemQueryStreamIterator(
+ sql,
+ requestOptions: requestOptions);
+
+ while (feedIterator.HasMoreResults)
+ {
+ ResponseMessage iter = await feedIterator.ReadNextAsync();
+ Assert.IsTrue(iter.IsSuccessStatusCode);
+ Assert.IsNull(iter.ErrorMessage);
+ totalRequstCharge += iter.Headers.RequestCharge;
+
+ ToDoActivity[] activities = TestCommon.SerializerCore.FromStream>(iter.Content).Data.ToArray();
+ Assert.AreEqual(1, activities.Length);
+ ToDoActivity response = activities.First();
+ resultList.Add(response);
+ }
+
+ Assert.AreEqual(deleteList.Count, resultList.Count);
+ Assert.IsTrue(totalRequstCharge > 0);
+
+ List verifiedOrderBy = deleteList.OrderBy(x => x.taskNum).ToList();
+ for (int i = 0; i < verifiedOrderBy.Count(); i++)
+ {
+ Assert.AreEqual(verifiedOrderBy[i].taskNum, resultList[i].taskNum);
+ Assert.AreEqual(verifiedOrderBy[i].id, resultList[i].id);
+ }
+ }
+ }
+ finally
+ {
+ System.Threading.Thread.CurrentThread.CurrentCulture = defaultCultureInfo;
+ }
+ }
+
+ ///
+ /// Validate multiple partition query
+ ///
+ [TestMethod]
+ public async Task ItemMultiplePartitionQueryStream()
+ {
+ IList deleteList = await ToDoActivity.CreateRandomItems(this.Container, 101, randomPartitionKey: true);
+ QueryDefinition sql = new QueryDefinition("SELECT * FROM toDoActivity t");
+
+ QueryRequestOptions requestOptions = new QueryRequestOptions()
+ {
+ MaxConcurrency = 5,
+ MaxItemCount = 5,
+ };
+
+ List resultList = new List();
+ double totalRequstCharge = 0;
+ FeedIterator feedIterator = this.Container.GetItemQueryStreamIterator(sql, requestOptions: requestOptions);
+ while (feedIterator.HasMoreResults)
+ {
+ ResponseMessage iter = await feedIterator.ReadNextAsync();
+ Assert.IsTrue(iter.IsSuccessStatusCode);
+ Assert.IsNull(iter.ErrorMessage);
+ totalRequstCharge += iter.Headers.RequestCharge;
+ ToDoActivity[] response = TestCommon.SerializerCore.FromStream>(iter.Content).Data.ToArray();
+ Assert.IsTrue(response.Length <= 5);
+ resultList.AddRange(response);
+ }
+
+ Assert.AreEqual(deleteList.Count, resultList.Count);
+ Assert.IsTrue(totalRequstCharge > 0);
+
+ List verifiedOrderBy = deleteList.OrderBy(x => x.id).ToList();
+ resultList = resultList.OrderBy(x => x.id).ToList();
+ for (int i = 0; i < verifiedOrderBy.Count(); i++)
+ {
+ Assert.AreEqual(verifiedOrderBy[i].taskNum, resultList[i].taskNum);
+ Assert.AreEqual(verifiedOrderBy[i].id, resultList[i].id);
+ }
+ }
+
+ ///
+ /// Validate multiple partition query
+ ///
+ [TestMethod]
+ public async Task ItemSinglePartitionQueryStream()
+ {
+ //Create a 101 random items with random guid PK values
+ IList deleteList = await ToDoActivity.CreateRandomItems(this.Container, pkCount: 101, perPKItemCount: 1, randomPartitionKey: true);
+
+ // Create 10 items with same pk value
+ IList findItems = await ToDoActivity.CreateRandomItems(this.Container, pkCount: 1, perPKItemCount: 10, randomPartitionKey: false);
+
+ string findPkValue = findItems.First().pk;
+ QueryDefinition sql = new QueryDefinition("SELECT * FROM toDoActivity t where t.pk = @pkValue").WithParameter("@pkValue", findPkValue);
+
+
+ double totalRequstCharge = 0;
+ FeedIterator setIterator = this.Container.GetItemQueryStreamIterator(
+ sql,
+ requestOptions: new QueryRequestOptions()
+ {
+ MaxConcurrency = 1,
+ PartitionKey = new Cosmos.PartitionKey(findPkValue),
+ });
+
+ List foundItems = new List();
+ while (setIterator.HasMoreResults)
+ {
+ ResponseMessage iter = await setIterator.ReadNextAsync();
+ Assert.IsTrue(iter.IsSuccessStatusCode);
+ Assert.IsNull(iter.ErrorMessage);
+ totalRequstCharge += iter.Headers.RequestCharge;
+ Collection response = TestCommon.SerializerCore.FromStream>(iter.Content).Data;
+ foundItems.AddRange(response);
+ }
+
+ Assert.AreEqual(findItems.Count, foundItems.Count);
+ Assert.IsFalse(foundItems.Any(x => !string.Equals(x.pk, findPkValue)), "All the found items should have the same PK value");
+ Assert.IsTrue(totalRequstCharge > 0);
+ }
+
+ [TestMethod]
+ public async Task EpkPointReadTest()
+ {
+ string pk = Guid.NewGuid().ToString();
+ string epk = new PartitionKey(pk)
+ .InternalKey
+ .GetEffectivePartitionKeyString(this.containerSettings.PartitionKey);
+
+ Dictionary properties = new Dictionary()
+ {
+ { WFConstants.BackendHeaders.EffectivePartitionKeyString, epk },
+ };
+
+ ItemRequestOptions itemRequestOptions = new ItemRequestOptions
+ {
+ IsEffectivePartitionKeyRouting = true,
+ Properties = properties,
+ };
+
+ ResponseMessage response = await this.Container.ReadItemStreamAsync(
+ Guid.NewGuid().ToString(),
+ Cosmos.PartitionKey.Null,
+ itemRequestOptions);
+
+ // Ideally it should be NotFound
+ // BadReqeust bcoz collection is regular and not binary
+ Assert.AreEqual(HttpStatusCode.BadRequest, response.StatusCode);
+
+ await this.Container.CreateItemAsync(new { id = Guid.NewGuid().ToString(), pk = "test" });
+ epk = new PartitionKey("test")
+ .InternalKey
+ .GetEffectivePartitionKeyString(this.containerSettings.PartitionKey);
+ properties = new Dictionary()
+ {
+ { WFConstants.BackendHeaders.EffectivePartitionKeyString, epk },
+ };
+
+ QueryRequestOptions queryRequestOptions = new QueryRequestOptions
+ {
+ IsEffectivePartitionKeyRouting = true,
+ Properties = properties,
+ };
+
+ using (FeedIterator resultSet = this.Container.GetItemQueryIterator(
+ queryText: "SELECT * FROM root",
+ requestOptions: queryRequestOptions))
+ {
+ FeedResponse feedresponse = await resultSet.ReadNextAsync();
+ Assert.IsNotNull(feedresponse.Resource);
+ Assert.AreEqual(1, feedresponse.Count());
+ }
+
+ }
+
+ ///
+ /// Validate that if the EPK is set in the options that only a single range is selected.
+ ///
+ [TestMethod]
+ public async Task ItemEpkQuerySingleKeyRangeValidation()
+ {
+ ContainerInternal container = null;
+ try
+ {
+ // Create a container large enough to have at least 2 partitions
+ ContainerResponse containerResponse = await this.database.CreateContainerAsync(
+ id: Guid.NewGuid().ToString(),
+ partitionKeyPath: "/pk",
+ throughput: 15000);
+ container = (ContainerInlineCore)containerResponse;
+
+ // Get all the partition key ranges to verify there is more than one partition
+ IRoutingMapProvider routingMapProvider = await this.GetClient().DocumentClient.GetPartitionKeyRangeCacheAsync(NoOpTrace.Singleton);
+ IReadOnlyList ranges = await routingMapProvider.TryGetOverlappingRangesAsync(
+ containerResponse.Resource.ResourceId,
+ new Documents.Routing.Range("00", "FF", isMaxInclusive: true, isMinInclusive: true),
+ NoOpTrace.Singleton,
+ forceRefresh: false);
+
+ // If this fails the RUs of the container needs to be increased to ensure at least 2 partitions.
+ Assert.IsTrue(ranges.Count > 1, " RUs of the container needs to be increased to ensure at least 2 partitions.");
+
+
+ ContainerQueryProperties containerQueryProperties = new ContainerQueryProperties(
+ containerResponse.Resource.ResourceId,
+ effectivePartitionKeyRanges: null,
+ //new List> { new Documents.Routing.Range("AA", "AA", true, true) },
+ containerResponse.Resource.PartitionKey,
+ vectorEmbeddingPolicy: null,
+ containerResponse.Resource.GeospatialConfig.GeospatialType);
+
+ // There should only be one range since the EPK option is set.
+ List partitionKeyRanges = await CosmosQueryExecutionContextFactory.GetTargetPartitionKeyRangesAsync(
+ queryClient: new CosmosQueryClientCore(container.ClientContext, container),
+ resourceLink: container.LinkUri,
+ partitionedQueryExecutionInfo: null,
+ containerQueryProperties: containerQueryProperties,
+ properties: new Dictionary()
+ {
+ {"x-ms-effective-partition-key-string", "AA" }
+ },
+ feedRangeInternal: null,
+ trace: NoOpTrace.Singleton);
+
+ Assert.IsTrue(partitionKeyRanges.Count == 1, "Only 1 partition key range should be selected since the EPK option is set.");
+
+ }
+ finally
+ {
+ if (container != null)
+ {
+ await container.DeleteContainerStreamAsync();
+ }
+ }
+ }
+
+ ///
+ /// Validate multiple partition query
+ ///
+ [TestMethod]
+ public async Task ItemQueryStreamSerializationSetting()
+ {
+ IList deleteList = await ToDoActivity.CreateRandomItems(
+ container: this.Container,
+ pkCount: 101,
+ randomTaskNumber: true);
+
+ QueryDefinition sql = new QueryDefinition("SELECT * FROM toDoActivity t ORDER BY t.taskNum");
+
+ CosmosSerializationFormatOptions options = new CosmosSerializationFormatOptions(
+ ContentSerializationFormat.CosmosBinary.ToString(),
+ (content) => JsonNavigator.Create(content),
+ () => JsonWriter.Create(JsonSerializationFormat.Binary));
+
+ QueryRequestOptions requestOptions = new QueryRequestOptions()
+ {
+ CosmosSerializationFormatOptions = options,
+ MaxConcurrency = 5,
+ MaxItemCount = 5,
+ };
+
+ List resultList = new List();
+ double totalRequstCharge = 0;
+ FeedIterator feedIterator = this.Container.GetItemQueryStreamIterator(
+ sql,
+ requestOptions: requestOptions);
+
+ while (feedIterator.HasMoreResults)
+ {
+ ResponseMessage response = await feedIterator.ReadNextAsync();
+ Assert.IsTrue(response.IsSuccessStatusCode);
+ Assert.IsNull(response.ErrorMessage);
+ totalRequstCharge += response.Headers.RequestCharge;
+
+ //Copy the stream and check that the first byte is the correct value
+ MemoryStream memoryStream = new MemoryStream();
+ response.Content.CopyTo(memoryStream);
+ byte[] content = memoryStream.ToArray();
+ response.Content.Position = 0;
+
+ // Examine the first buffer byte to determine the serialization format
+ byte firstByte = content[0];
+ Assert.AreEqual(128, firstByte);
+ Assert.AreEqual(JsonSerializationFormat.Binary, (JsonSerializationFormat)firstByte);
+
+ IJsonReader reader = JsonReader.Create(content);
+ IJsonWriter textWriter = JsonWriter.Create(JsonSerializationFormat.Text);
+ reader.WriteAll(textWriter);
+ string json = Encoding.UTF8.GetString(textWriter.GetResult().ToArray());
+ Assert.IsNotNull(json);
+ ToDoActivity[] responseActivities = JsonConvert.DeserializeObject>(json).Data.ToArray();
+ Assert.IsTrue(responseActivities.Length <= 5);
+ resultList.AddRange(responseActivities);
+ }
+
+ Assert.AreEqual(deleteList.Count, resultList.Count);
+ Assert.IsTrue(totalRequstCharge > 0);
+
+ List verifiedOrderBy = deleteList.OrderBy(x => x.taskNum).ToList();
+ for (int i = 0; i < verifiedOrderBy.Count(); i++)
+ {
+ Assert.AreEqual(verifiedOrderBy[i].taskNum, resultList[i].taskNum);
+ Assert.AreEqual(verifiedOrderBy[i].id, resultList[i].id);
+ }
+ }
+
+ ///
+ /// Validate that the max item count works correctly.
+ ///
+ ///
+ [TestMethod]
+ public async Task ValidateMaxItemCountOnItemQuery()
+ {
+ IList deleteList = await ToDoActivity.CreateRandomItems(container: this.Container, pkCount: 1, perPKItemCount: 6, randomPartitionKey: false);
+
+ ToDoActivity toDoActivity = deleteList.First();
+ QueryDefinition sql = new QueryDefinition(
+ "select * from toDoActivity t where t.pk = @pk")
+ .WithParameter("@pk", toDoActivity.pk);
+
+ // Test max size at 1
+ FeedIterator feedIterator = this.Container.GetItemQueryIterator(
+ sql,
+ requestOptions: new QueryRequestOptions()
+ {
+ MaxItemCount = 1,
+ PartitionKey = new Cosmos.PartitionKey(toDoActivity.pk),
+ });
+
+ while (feedIterator.HasMoreResults)
+ {
+ FeedResponse iter = await feedIterator.ReadNextAsync();
+ Assert.AreEqual(1, iter.Count());
+ }
+
+ // Test max size at 2
+ FeedIterator setIteratorMax2 = this.Container.GetItemQueryIterator(
+ sql,
+ requestOptions: new QueryRequestOptions()
+ {
+ MaxItemCount = 2,
+ PartitionKey = new Cosmos.PartitionKey(toDoActivity.pk),
+ });
+
+ while (setIteratorMax2.HasMoreResults)
+ {
+ FeedResponse iter = await setIteratorMax2.ReadNextAsync();
+ Assert.AreEqual(2, iter.Count());
+ }
+ }
+
+ ///
+ /// Validate that the max item count works correctly.
+ ///
+ ///
+ [TestMethod]
+ public async Task NegativeQueryTest()
+ {
+ await ToDoActivity.CreateRandomItems(container: this.Container, pkCount: 10, perPKItemCount: 20, randomPartitionKey: true);
+
+ try
+ {
+ using (FeedIterator resultSet = this.Container.GetItemQueryIterator(
+ queryText: "SELECT r.id FROM root r WHERE r._ts > 0",
+ requestOptions: new QueryRequestOptions()
+ {
+ ResponseContinuationTokenLimitInKb = 0,
+ MaxItemCount = 10,
+ MaxConcurrency = 1
+ }))
+ {
+ await resultSet.ReadNextAsync();
+ }
+ Assert.Fail("Expected query to fail");
+ }
+ catch (CosmosException exception) when (exception.StatusCode == HttpStatusCode.BadRequest)
+ {
+ Assert.IsTrue(exception.Message.Contains("continuation token limit specified is not large enough"), exception.Message);
+ }
+
+ try
+ {
+ using (FeedIterator resultSet = this.Container.GetItemQueryIterator(
+ queryText: "SELECT r.id FROM root r WHERE r._ts >!= 0",
+ requestOptions: new QueryRequestOptions() { MaxConcurrency = 1 }))
+ {
+ await resultSet.ReadNextAsync();
+ }
+ Assert.Fail("Expected query to fail");
+ }
+ catch (CosmosException exception) when (exception.StatusCode == HttpStatusCode.BadRequest)
+ {
+ Assert.IsTrue(exception.Message.Contains("Syntax error, incorrect syntax near"), exception.Message);
+ }
+ }
+
[TestMethod]
- public async Task ItemCustomSerializerTest()
+ [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
+ [DataRow(false, DisplayName = "Test scenario when binary encoding is disabled at client level.")]
+ public async Task ItemRequestOptionAccessConditionTest(bool binaryEncodingEnabledInClient)
{
- DateTime createDateTime = DateTime.UtcNow;
- Dictionary keyValuePairs = new Dictionary()
- {
- {"test1", 42 },
- {"test42", 9001 }
- };
-
- dynamic testItem1 = new
- {
- id = "ItemCustomSerialzierTest1",
- cost = (double?)null,
- totalCost = 98.2789,
- pk = "MyCustomStatus",
- taskNum = 4909,
- createdDateTime = createDateTime,
- statusCode = HttpStatusCode.Accepted,
- itemIds = new int[] { 1, 5, 10 },
- dictionary = keyValuePairs
- };
-
- dynamic testItem2 = new
- {
- id = "ItemCustomSerialzierTest2",
- cost = (double?)null,
- totalCost = 98.2789,
- pk = "MyCustomStatus",
- taskNum = 4909,
- createdDateTime = createDateTime,
- statusCode = HttpStatusCode.Accepted,
- itemIds = new int[] { 1, 5, 10 },
- dictionary = keyValuePairs
- };
-
- JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings()
- {
- Converters = new List() { new CosmosSerializerHelper.FormatNumbersAsTextConverter() }
- };
-
- List queryDefinitions = new List()
+ try
{
- new QueryDefinition("select * from t where t.pk = @pk" ).WithParameter("@pk", testItem1.pk),
- new QueryDefinition("select * from t where t.cost = @cost" ).WithParameter("@cost", testItem1.cost),
- new QueryDefinition("select * from t where t.taskNum = @taskNum" ).WithParameter("@taskNum", testItem1.taskNum),
- new QueryDefinition("select * from t where t.totalCost = @totalCost" ).WithParameter("@totalCost", testItem1.totalCost),
- new QueryDefinition("select * from t where t.createdDateTime = @createdDateTime" ).WithParameter("@createdDateTime", testItem1.createdDateTime),
- new QueryDefinition("select * from t where t.statusCode = @statusCode" ).WithParameter("@statusCode", testItem1.statusCode),
- new QueryDefinition("select * from t where t.itemIds = @itemIds" ).WithParameter("@itemIds", testItem1.itemIds),
- new QueryDefinition("select * from t where t.dictionary = @dictionary" ).WithParameter("@dictionary", testItem1.dictionary),
- new QueryDefinition("select * from t where t.pk = @pk and t.cost = @cost" )
- .WithParameter("@pk", testItem1.pk)
- .WithParameter("@cost", testItem1.cost),
- };
-
- int toStreamCount = 0;
- int fromStreamCount = 0;
- CosmosSerializerHelper cosmosSerializerHelper = new CosmosSerializerHelper(
- jsonSerializerSettings,
- toStreamCallBack: (itemValue) =>
+ if (binaryEncodingEnabledInClient)
{
- Type itemType = itemValue?.GetType();
- if (itemValue == null
- || itemType == typeof(int)
- || itemType == typeof(double)
- || itemType == typeof(string)
- || itemType == typeof(DateTime)
- || itemType == typeof(HttpStatusCode)
- || itemType == typeof(int[])
- || itemType == typeof(Dictionary))
- {
- toStreamCount++;
- }
- },
- fromStreamCallback: (item) => fromStreamCount++);
-
- CosmosClientOptions options = new CosmosClientOptions()
- {
- Serializer = cosmosSerializerHelper
- };
-
- CosmosClient clientSerializer = TestCommon.CreateCosmosClient(options);
- Container containerSerializer = clientSerializer.GetContainer(this.database.Id, this.Container.Id);
+ Environment.SetEnvironmentVariable(ConfigurationManager.BinaryEncodingEnabled, "True");
+ }
- try
- {
- await containerSerializer.CreateItemAsync(testItem1);
- await containerSerializer.CreateItemAsync(testItem2);
- }
- catch (CosmosException ex) when (ex.StatusCode == HttpStatusCode.Conflict)
- {
- // Ignore conflicts since the object already exists
- }
+ // Create an item
+ ToDoActivity testItem = (await ToDoActivity.CreateRandomItems(this.Container, 1, randomPartitionKey: true)).First();
- foreach (QueryDefinition queryDefinition in queryDefinitions)
- {
- toStreamCount = 0;
- fromStreamCount = 0;
+ ItemRequestOptions itemRequestOptions = new ItemRequestOptions()
+ {
+ IfMatchEtag = Guid.NewGuid().ToString(),
+ };
- List allItems = new List();
- int pageCount = 0;
- using (FeedIterator feedIterator = containerSerializer.GetItemQueryIterator(
- queryDefinition: queryDefinition))
+ using (ResponseMessage responseMessage = await this.Container.UpsertItemStreamAsync(
+ streamPayload: TestCommon.SerializerCore.ToStream(testItem),
+ partitionKey: new Cosmos.PartitionKey(testItem.pk),
+ requestOptions: itemRequestOptions))
{
- while (feedIterator.HasMoreResults)
- {
- // Only need once to verify correct serialization of the query definition
- FeedResponse response = await feedIterator.ReadNextAsync(this.cancellationToken);
- Assert.AreEqual(response.Count, response.Count());
- allItems.AddRange(response);
- pageCount++;
- }
+ Assert.IsNotNull(responseMessage);
+ Assert.IsNull(responseMessage.Content);
+ Assert.AreEqual(HttpStatusCode.PreconditionFailed, responseMessage.StatusCode, responseMessage.ErrorMessage);
+ Assert.AreNotEqual(responseMessage.Headers.ActivityId, Guid.Empty);
+ Assert.IsTrue(responseMessage.Headers.RequestCharge > 0);
+ Assert.IsFalse(string.IsNullOrEmpty(responseMessage.ErrorMessage));
+ Assert.IsTrue(responseMessage.ErrorMessage.Contains("One of the specified pre-condition is not met"));
}
- Assert.AreEqual(2, allItems.Count, $"missing query results. Only found: {allItems.Count} items for query:{queryDefinition.ToSqlQuerySpec().QueryText}");
- foreach (dynamic item in allItems)
+ try
{
- Assert.IsFalse(string.Equals(testItem1.id, item.id) || string.Equals(testItem2.id, item.id));
- Assert.IsTrue(((JObject)item)["totalCost"].Type == JTokenType.String);
- Assert.IsTrue(((JObject)item)["taskNum"].Type == JTokenType.String);
+ ItemResponse response = await this.Container.UpsertItemAsync(
+ item: testItem,
+ requestOptions: itemRequestOptions);
+ Assert.Fail("Access condition should have failed");
+ }
+ catch (CosmosException e)
+ {
+ Assert.IsNotNull(e);
+ Assert.AreEqual(HttpStatusCode.PreconditionFailed, e.StatusCode, e.Message);
+ Assert.AreNotEqual(e.ActivityId, Guid.Empty);
+ Assert.IsTrue(e.RequestCharge > 0);
+ string expectedResponseBody = $"{Environment.NewLine}Errors : [{Environment.NewLine} \"One of the specified pre-condition is not met. Learn more: https://aka.ms/CosmosDB/sql/errors/precondition-failed\"{Environment.NewLine}]{Environment.NewLine}";
+ Assert.AreEqual(expectedResponseBody, e.ResponseBody);
+ string expectedMessage = $"Response status code does not indicate success: PreconditionFailed (412); Substatus: 0; ActivityId: {e.ActivityId}; Reason: ({expectedResponseBody});";
+ Assert.AreEqual(expectedMessage, e.Message);
+ }
+ finally
+ {
+ ItemResponse deleteResponse = await this.Container.DeleteItemAsync(partitionKey: new Cosmos.PartitionKey(testItem.pk), id: testItem.id);
+ Assert.IsNotNull(deleteResponse);
}
-
- // Each parameter in query spec should be a call to the custom serializer
- int parameterCount = queryDefinition.ToSqlQuerySpec().Parameters.Count;
- Assert.AreEqual((parameterCount * pageCount) + parameterCount, toStreamCount, $"missing to stream call. Expected: {(parameterCount * pageCount) + parameterCount}, Actual: {toStreamCount} for query:{queryDefinition.ToSqlQuerySpec().QueryText}");
- Assert.AreEqual(pageCount, fromStreamCount);
}
- }
-
+ finally
+ {
+ Environment.SetEnvironmentVariable(ConfigurationManager.BinaryEncodingEnabled, null);
+ }
+ }
+
[TestMethod]
- public async Task QueryStreamValueTest()
+ [DataRow(true, DisplayName = "Test scenario when binary encoding is enabled at client level.")]
+ [DataRow(false, DisplayName = "Test scenario when binary encoding is disabled at client level.")]
+ public async Task ItemReplaceAsyncTest(bool binaryEncodingEnabledInClient)
{
- DateTime createDateTime = DateTime.UtcNow;
-
- dynamic testItem1 = new
- {
- id = "testItem1",
- cost = (double?)null,
- totalCost = 98.2789,
- pk = "MyCustomStatus",
- taskNum = 4909,
- createdDateTime = createDateTime,
- statusCode = HttpStatusCode.Accepted,
- itemIds = new int[] { 1, 5, 10 },
- itemcode = new byte?[5] { 0x16, (byte)'\0', 0x3, null, (byte)'}' },
- };
-
- dynamic testItem2 = new
- {
- id = "testItem2",
- cost = (double?)null,
- totalCost = 98.2789,
- pk = "MyCustomStatus",
- taskNum = 4909,
- createdDateTime = createDateTime,
- statusCode = HttpStatusCode.Accepted,
- itemIds = new int[] { 1, 5, 10 },
- itemcode = new byte?[5] { 0x16, (byte)'\0', 0x3, null, (byte)'}' },
- };
-
- //with Custom Serializer.
- JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings()
+ try
{
- Converters = new List() { new CosmosSerializerHelper.FormatNumbersAsTextConverter() }
- };
-
- int toStreamCount = 0;
- int fromStreamCount = 0;
- CosmosSerializerHelper cosmosSerializerHelper = new CosmosSerializerHelper(
- jsonSerializerSettings,
- toStreamCallBack: (itemValue) =>
+ if (binaryEncodingEnabledInClient)
{
- Type itemType = itemValue?.GetType();
- if (itemValue == null
- || itemType == typeof(int)
- || itemType == typeof(double)
- || itemType == typeof(string)
- || itemType == typeof(DateTime)
- || itemType == typeof(HttpStatusCode)
- || itemType == typeof(int[])
- || itemType == typeof(byte))
- {
- toStreamCount++;
- }
- },
- fromStreamCallback: (item) => fromStreamCount++);
+ Environment.SetEnvironmentVariable(ConfigurationManager.BinaryEncodingEnabled, "True");
+ }
- CosmosClientOptions options = new CosmosClientOptions()
- {
- Serializer = cosmosSerializerHelper
- };
+ // Create an item
+ ToDoActivity testItem = (await ToDoActivity.CreateRandomItems(this.Container, 1, randomPartitionKey: true)).First();
- CosmosClient clientSerializer = TestCommon.CreateCosmosClient(options);
- Container containerSerializer = clientSerializer.GetContainer(this.database.Id, this.Container.Id);
+ string originalId = testItem.id;
+ testItem.id = Guid.NewGuid().ToString();
- List queryDefinitions = new List()
- {
- new QueryDefinition("select * from t where t.pk = @pk" )
- .WithParameterStream("@pk", cosmosSerializerHelper.ToStream(testItem1.pk)),
- new QueryDefinition("select * from t where t.cost = @cost" )
- .WithParameterStream("@cost", cosmosSerializerHelper.ToStream(testItem1.cost)),
- new QueryDefinition("select * from t where t.taskNum = @taskNum" )
- .WithParameterStream("@taskNum", cosmosSerializerHelper.ToStream(testItem1.taskNum)),
- new QueryDefinition("select * from t where t.totalCost = @totalCost" )
- .WithParameterStream("@totalCost", cosmosSerializerHelper.ToStream(testItem1.totalCost)),
- new QueryDefinition("select * from t where t.createdDateTime = @createdDateTime" )
- .WithParameterStream("@createdDateTime", cosmosSerializerHelper.ToStream(testItem1.createdDateTime)),
- new QueryDefinition("select * from t where t.statusCode = @statusCode" )
- .WithParameterStream("@statusCode", cosmosSerializerHelper.ToStream(testItem1.statusCode)),
- new QueryDefinition("select * from t where t.itemIds = @itemIds" )
- .WithParameterStream("@itemIds", cosmosSerializerHelper.ToStream(testItem1.itemIds)),
- new QueryDefinition("select * from t where t.itemcode = @itemcode" )
- .WithParameterStream("@itemcode", cosmosSerializerHelper.ToStream(testItem1.itemcode)),
- new QueryDefinition("select * from t where t.pk = @pk and t.cost = @cost" )
- .WithParameterStream("@pk", cosmosSerializerHelper.ToStream(testItem1.pk))
- .WithParameterStream("@cost", cosmosSerializerHelper.ToStream(testItem1.cost)),
- };
+ ItemResponse response = await this.Container.ReplaceItemAsync(
+ id: originalId,
+ item: testItem);
- try
- {
- await containerSerializer.CreateItemAsync(testItem1);
- await containerSerializer.CreateItemAsync(testItem2);
- }
- catch (CosmosException ex) when (ex.StatusCode == HttpStatusCode.Conflict)
- {
- // Ignore conflicts since the object already exists
- }
+ Assert.AreEqual(testItem.id, response.Resource.id);
+ Assert.AreNotEqual(originalId, response.Resource.id);
- foreach (QueryDefinition queryDefinition in queryDefinitions)
- {
- toStreamCount = 0;
- fromStreamCount = 0;
+ string originalStatus = testItem.pk;
+ testItem.pk = Guid.NewGuid().ToString();
- List allItems = new List();
- int pageCount = 0;
- using (FeedIterator feedIterator = containerSerializer.GetItemQueryIterator(
- queryDefinition: queryDefinition))
+ try
{
- while (feedIterator.HasMoreResults)
- {
- // Only need once to verify correct serialization of the query definition
- FeedResponse response = await feedIterator.ReadNextAsync(this.cancellationToken);
- string diagnosticString = response.Diagnostics.ToString();
- Assert.IsTrue(diagnosticString.Contains("Query Response Serialization"));
- Assert.AreEqual(response.Count, response.Count());
- allItems.AddRange(response);
- pageCount++;
- }
+ response = await this.Container.ReplaceItemAsync(
+ id: testItem.id,
+ partitionKey: new Cosmos.PartitionKey(originalStatus),
+ item: testItem);
+ Assert.Fail("Replace changing partition key is not supported.");
+ }
+ catch (CosmosException ce)
+ {
+ Assert.AreEqual((HttpStatusCode)400, ce.StatusCode);
}
-
- Assert.AreEqual(2, allItems.Count, $"missing query results. Only found: {allItems.Count} items for query:{queryDefinition.ToSqlQuerySpec().QueryText}");
-
- // There should be no call to custom serializer since the parameter values are already serialized.
- Assert.AreEqual(0, toStreamCount, $"missing to stream call. Expected: 0 , Actual: {toStreamCount} for query:{queryDefinition.ToSqlQuerySpec().QueryText}");
- Assert.AreEqual(pageCount, fromStreamCount);
}
-
- // get result across pages,multiple requests by setting MaxItemCount to 1.
- foreach (QueryDefinition queryDefinition in queryDefinitions)
+ finally
+ {
+ Environment.SetEnvironmentVariable(ConfigurationManager.BinaryEncodingEnabled, null);
+ }
+ }
+
+ [TestMethod]
+ public async Task ItemPatchFailureTest()
+ {
+ // Create an item
+ ToDoActivity testItem = (await ToDoActivity.CreateRandomItems(this.Container, 1, randomPartitionKey: true)).First();
+ ContainerInternal containerInternal = (ContainerInternal)this.Container;
+
+ List patchOperations = new List
+ {
+ PatchOperation.Add("/nonExistentParent/Child", "bar"),
+ PatchOperation.Remove("/cost")
+ };
+
+ // item does not exist - 404 Resource Not Found error
+ try
+ {
+ await containerInternal.PatchItemAsync(
+ id: Guid.NewGuid().ToString(),
+ partitionKey: new Cosmos.PartitionKey(testItem.pk),
+ patchOperations: patchOperations);
+
+ Assert.Fail("Patch operation should fail if the item doesn't exist.");
+ }
+ catch (CosmosException ex)
+ {
+ Assert.AreEqual(HttpStatusCode.NotFound, ex.StatusCode);
+ Assert.IsTrue(ex.Message.Contains("Resource Not Found"));
+ Assert.IsTrue(ex.Message.Contains("https://aka.ms/cosmosdb-tsg-not-found"));
+ CosmosItemTests.ValidateCosmosException(ex);
+ }
+
+ // adding a child when parent / ancestor does not exist - 400 BadRequest response
+ try
+ {
+ await containerInternal.PatchItemAsync(
+ id: testItem.id,
+ partitionKey: new Cosmos.PartitionKey(testItem.pk),
+ patchOperations: patchOperations);
+
+ Assert.Fail("Patch operation should fail for malformed PatchSpecification.");
+ }
+ catch (CosmosException ex)
+ {
+ Assert.AreEqual(HttpStatusCode.BadRequest, ex.StatusCode);
+ Assert.IsTrue(ex.Message.Contains(@"For Operation(1): Add Operation can only create a child object of an existing node(array or object) and cannot create path recursively, no path found beyond: 'nonExistentParent'. Learn more: https://aka.ms/cosmosdbpatchdocs"), ex.Message);
+ CosmosItemTests.ValidateCosmosException(ex);
+ }
+
+ // precondition failure - 412 response
+ PatchItemRequestOptions requestOptions = new PatchItemRequestOptions()
+ {
+ IfMatchEtag = Guid.NewGuid().ToString()
+ };
+
+ try
+ {
+ await containerInternal.PatchItemAsync(
+ id: testItem.id,
+ partitionKey: new Cosmos.PartitionKey(testItem.pk),
+ patchOperations: patchOperations,
+ requestOptions);
+
+ Assert.Fail("Patch operation should fail in case of pre-condition failure.");
+ }
+ catch (CosmosException ex)
+ {
+ Assert.AreEqual(HttpStatusCode.PreconditionFailed, ex.StatusCode);
+ Assert.IsTrue(ex.Message.Contains("One of the specified pre-condition is not met"));
+ CosmosItemTests.ValidateCosmosException(ex);
+ }
+ }
+
+ [TestMethod]
+ public async Task ItemPatchSuccessTest()
+ {
+ // Create an item
+ ToDoActivity testItem = (await ToDoActivity.CreateRandomItems(this.Container, 1, randomPartitionKey: true)).First();
+ ContainerInternal containerInternal = (ContainerInternal)this.Container;
+
+ int originalTaskNum = testItem.taskNum;
+ int newTaskNum = originalTaskNum + 1;
+ //Int16 one = 1;
+
+ Assert.IsNull(testItem.children[1].pk);
+ List patchOperations = new List()
+ {
+ PatchOperation.Set("/children/0/description", "testSet"),
+ PatchOperation.Add("/children/1/pk", "patched"),
+ PatchOperation.Remove("/description"),
+ PatchOperation.Replace("/taskNum", newTaskNum),
+ //PatchOperation.Increment("/taskNum", one)
+
+ PatchOperation.Set