From 065efc74ae929e11374bba61d04ec78d1e35ae83 Mon Sep 17 00:00:00 2001 From: philipthomas Date: Sat, 14 Oct 2023 16:23:37 -0400 Subject: [PATCH 1/5] issue 4115 initial checkin. need insight from issuer on reproducing this issue --- .../CosmosExceptionFactory.cs | 5 + .../CosmosItemTests.cs | 111 ++++++++++++++++-- 2 files changed, 104 insertions(+), 12 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExceptionFactory.cs b/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExceptionFactory.cs index 0648aecbc3..b97121071d 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExceptionFactory.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExceptionFactory.cs @@ -182,6 +182,11 @@ internal static (Error, string) GetErrorFromStream( catch (Newtonsoft.Json.JsonReaderException) { } + // Suggested resolution. However, for the purpose of TDD and failing a test, I am commenting this out. + //////catch (Exception exception) when (exception is Newtonsoft.Json.JsonReaderException || + ////// exception is Newtonsoft.Json.JsonSerializationException) + //////{ + //////} // Content is not Json content.Position = 0; 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 607b552b83..051325e60e 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs @@ -781,7 +781,7 @@ public async Task PartitionKeyDeleteTestForSubpartitionedContainer() try { database = await client.CreateDatabaseIfNotExistsAsync("mydb"); - + ContainerProperties containerProperties = new ContainerProperties("subpartitionedcontainer", new List { "/Country", "/City" }); Container container = await database.CreateContainerAsync(containerProperties); ContainerInternal containerInternal = (ContainerInternal)container; @@ -812,7 +812,7 @@ public async Task PartitionKeyDeleteTestForSubpartitionedContainer() doc1.SetValue("Country", "USA"); doc1.SetValue("City", "Stonybrook"); documents[4] = await container.CreateItemAsync(doc1); - + Cosmos.PartitionKey partitionKey1 = new PartitionKeyBuilder().Add("USA").Add("Stonybrook").Build(); using (ResponseMessage pKDeleteResponse = await containerInternal.DeleteAllItemsByPartitionKeyStreamAsync(partitionKey1)) @@ -844,7 +844,7 @@ public async Task PartitionKeyDeleteTestForSubpartitionedContainer() finally { HttpConstants.Versions.CurrentVersion = currentVersion; - if(database != null) await database.DeleteAsync(); + if (database != null) await database.DeleteAsync(); } } @@ -973,7 +973,7 @@ public async Task ItemCustomSerializerTest() // 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((parameterCount * pageCount) + parameterCount, toStreamCount, $"missing to stream call. Expected: {(parameterCount * pageCount) + parameterCount}, Actual: {toStreamCount} for query:{queryDefinition.ToSqlQuerySpec().QueryText}"); Assert.AreEqual(pageCount, fromStreamCount); } } @@ -1195,7 +1195,7 @@ public async Task QueryStreamValueTest() { Assert.AreEqual(3, pageCount); } - + IReadOnlyList<(string Name, object Value)> parameters1 = queryDefinition.GetQueryParameters(); @@ -1362,7 +1362,7 @@ public async Task ItemMultiplePartitionQuery() { FeedResponse iter = await feedIterator.ReadNextAsync(); Assert.IsTrue(iter.Count() <= 1); - if(iter.Count() == 1) + if (iter.Count() == 1) { found = true; ToDoActivity response = iter.First(); @@ -1493,8 +1493,8 @@ public async Task ItemMultiplePartitionOrderByQueryStream() }; IList deleteList = await ToDoActivity.CreateRandomItems( - this.Container, - 300, + this.Container, + 300, randomPartitionKey: true, randomTaskNumber: true); @@ -1753,8 +1753,8 @@ public async Task ItemEpkQuerySingleKeyRangeValidation() public async Task ItemQueryStreamSerializationSetting() { IList deleteList = await ToDoActivity.CreateRandomItems( - container: this.Container, - pkCount: 101, + container: this.Container, + pkCount: 101, randomTaskNumber: true); QueryDefinition sql = new QueryDefinition("SELECT * FROM toDoActivity t ORDER BY t.taskNum"); @@ -2135,9 +2135,9 @@ public async Task ItemPatchSuccessTest() Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); Assert.IsNotNull(response.Resource); Assert.AreEqual(null, response.Resource.children[0].id); - + patchOperations.Clear(); - patchOperations.Add(PatchOperation.Add("/children/1/description","Child#1")); + patchOperations.Add(PatchOperation.Add("/children/1/description", "Child#1")); patchOperations.Add(PatchOperation.Move("/children/0/description", "/description")); patchOperations.Add(PatchOperation.Move("/children/1/description", "/children/0/description")); // with content response @@ -3151,6 +3151,93 @@ public async Task HaLayerDoesNotThrowNullOnGoneExceptionTest() } } + /// + /// + /// + /// + [TestMethod] + [Owner("philipthomas")] + [Description("Fix: ReadItemAsync/ReadItemStreamAsync is yielding a Newtonsoft.Json.JsonSerializationException whenever " + + "the item is not found and the custom serializer has MissingMemberHandling set to MissingMemberHandling.Error. " + + "ReadItemAsync/ReadItemStreamAsync should yield a CosmosException with a NotFound StatusCode.")] + public async Task GivenReadItemAsyncSerializationExceptionWhenMissingMemberHandlingIsErrorThenExpectsCosmosExceptionTestAsync() + { + // AAA + // Arrange + CancellationTokenSource cancellationTokenSource = new(); + CancellationToken cancellationToken = cancellationTokenSource.Token; + + int toStreamCount = 0; + int fromStreamCount = 0; + CosmosSerializerHelper serializer = new( + jsonSerializerSettings: new JsonSerializerSettings() + { + NullValueHandling = NullValueHandling.Ignore, + MissingMemberHandling = MissingMemberHandling.Error, + }, + fromStreamCallback: item => fromStreamCount++, + toStreamCallBack: item => toStreamCount++); + + CosmosClient cosmosClient = TestCommon.CreateCosmosClient(customizeClientBuilder: builder => builder.WithCustomSerializer(cosmosJsonSerializer: serializer)); + + string databaseId = Guid.NewGuid().ToString(); + Cosmos.Database database = await cosmosClient.CreateDatabaseIfNotExistsAsync( + id: databaseId, + cancellationToken: cancellationToken); + + try + { + string containerId = Guid.NewGuid().ToString(); + Container container = await database.CreateContainerIfNotExistsAsync( + containerProperties: new ContainerProperties + { + Id = containerId, + PartitionKeyPath = "/pk", + }, + cancellationToken: cancellationToken); + + + // Act + // If any thing other than a CosmosException is thrown, the call to ReadItemAsync below will fail. + string itemIdThatWillNotExist = Guid.NewGuid().ToString(); + string partitionKeyValue = "Washington"; + CosmosException cosmosException = await Assert.ThrowsExceptionAsync(action: + async () => await container.ReadItemAsync( + id: itemIdThatWillNotExist, + partitionKey: new Cosmos.PartitionKey(partitionKeyValue), + cancellationToken: cancellationToken)); + + Debug.Assert( + condition: cosmosException != null, + message: $"{cosmosException}"); + + Debug.WriteLine(message: $"{nameof(cosmosException)}: {cosmosException}"); + + // Assert + Assert.AreEqual( + actual: cosmosException.StatusCode, + expected: HttpStatusCode.NotFound); + } + catch (JsonSerializationException jsonSerializationException) + { + Assert.Fail(message: $"JsonSerializationException was caught, so fail the test. {jsonSerializationException}."); + } + catch (Exception otherException) + { + Assert.Fail(message: $"Any other exception is thrown before the Act, so fail the test. {otherException}."); + } + finally + { + if (database != null) + { + // Remove the test database. Cleanup. + _ = await database.DeleteAsync(cancellationToken: cancellationToken); + + Debug.WriteLine($"The {nameof(database)} with id '{databaseId}' was removed."); + } + } + } + private async Task AutoGenerateIdPatternTest(Cosmos.PartitionKey pk, T itemWithoutId) { string autoId = Guid.NewGuid().ToString(); From 048e019e421ce3b35b3367066a122bb98f1c85dd Mon Sep 17 00:00:00 2001 From: philipthomas Date: Tue, 17 Oct 2023 11:03:02 -0400 Subject: [PATCH 2/5] test refactoring and adding more coverage for other NotFound scenarios --- .../CosmosExceptionFactory.cs | 14 +- .../CosmosItemTests.cs | 279 ++++++++++++++++-- 2 files changed, 266 insertions(+), 27 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExceptionFactory.cs b/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExceptionFactory.cs index b97121071d..741f8906fa 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExceptionFactory.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExceptionFactory.cs @@ -159,6 +159,7 @@ internal static (Error, string) GetErrorFromStream( using (StreamReader streamReader = new StreamReader(content)) { string errorContent = streamReader.ReadToEnd(); + try { JObject errorObj = JObject.Parse(errorContent); @@ -179,14 +180,9 @@ internal static (Error, string) GetErrorFromStream( return (error, message.ToString()); } } - catch (Newtonsoft.Json.JsonReaderException) + catch (Exception exception) when (CosmosExceptionFactory.ExceptionsToIgnore(exception)) { } - // Suggested resolution. However, for the purpose of TDD and failing a test, I am commenting this out. - //////catch (Exception exception) when (exception is Newtonsoft.Json.JsonReaderException || - ////// exception is Newtonsoft.Json.JsonSerializationException) - //////{ - //////} // Content is not Json content.Position = 0; @@ -198,6 +194,12 @@ internal static (Error, string) GetErrorFromStream( } } + private static bool ExceptionsToIgnore(Exception exception) + { + return exception is Newtonsoft.Json.JsonReaderException || + exception is Newtonsoft.Json.JsonSerializationException; + } + internal static CosmosException CreateRequestTimeoutException( string message, Headers headers, 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 051325e60e..4a79beb4c8 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs @@ -3157,28 +3157,267 @@ public async Task HaLayerDoesNotThrowNullOnGoneExceptionTest() /// [TestMethod] [Owner("philipthomas")] - [Description("Fix: ReadItemAsync/ReadItemStreamAsync is yielding a Newtonsoft.Json.JsonSerializationException whenever " + - "the item is not found and the custom serializer has MissingMemberHandling set to MissingMemberHandling.Error. " + - "ReadItemAsync/ReadItemStreamAsync should yield a CosmosException with a NotFound StatusCode.")] - public async Task GivenReadItemAsyncSerializationExceptionWhenMissingMemberHandlingIsErrorThenExpectsCosmosExceptionTestAsync() + [Description("ReadItemStreamAsync is yielding a Newtonsoft.Json.JsonSerializationException whenever " + + "the item is not found and the MissingMemberHandling is set to MissingMemberHandling.Error. " + + "ReadItemStreamAsync should yield a CosmosException with a NotFound StatusCode.")] + public async Task GivenReadItemStreamAsyncWhenMissingMemberHandlingIsErrorThenExpectsCosmosExceptionTestAsync() + { + await CosmosItemTests.GivenItemStreamAsyncWhenMissingMemberHandlingIsErrorThenExpectsCosmosExceptionTestAsync( + itemStreamAsync: async (container, itemIdThatWillNotExist, partitionKeyValue, cancellationToken) => await container.ReadItemStreamAsync( + id: itemIdThatWillNotExist, + partitionKey: new Cosmos.PartitionKey(partitionKeyValue), + cancellationToken: cancellationToken)); + } + + /// + /// + /// + /// + [TestMethod] + [Owner("philipthomas")] + [Description("ReadItemAsync is yielding a Newtonsoft.Json.JsonSerializationException whenever " + + "the item is not found and MissingMemberHandling is set to MissingMemberHandling.Error. " + + "ReadItemAsync should yield a CosmosException with a NotFound StatusCode.")] + public async Task GivenReadItemAsyncWhenMissingMemberHandlingIsErrorThenExpectsCosmosExceptionTestAsync() + { + await CosmosItemTests.GivenItemAsyncWhenMissingMemberHandlingIsErrorThenExpectsCosmosExceptionTestAsync( + itemAsync: async (container, itemIdThatWillNotExist, partitionKeyValue, toDoActivity, cancellationToken) => await container.ReadItemAsync( + id: itemIdThatWillNotExist, + partitionKey: new Cosmos.PartitionKey(partitionKeyValue), + cancellationToken: cancellationToken)); + } + + /// + /// + /// + /// + [TestMethod] + [Owner("philipthomas")] + [Description("DeleteItemStreamAsync is yielding a Newtonsoft.Json.JsonSerializationException whenever " + + "the item is not found and the MissingMemberHandling is set to MissingMemberHandling.Error. " + + "DeleteItemStreamAsync should yield a CosmosException with a NotFound StatusCode.")] + public async Task GivenDeleteItemStreamAsyncWhenMissingMemberHandlingIsErrorThenExpectsCosmosExceptionTestAsync() + { + await CosmosItemTests.GivenItemStreamAsyncWhenMissingMemberHandlingIsErrorThenExpectsCosmosExceptionTestAsync( + itemStreamAsync: async (container, itemIdThatWillNotExist, partitionKeyValue, cancellationToken) => await container.DeleteItemStreamAsync( + id: itemIdThatWillNotExist, + partitionKey: new Cosmos.PartitionKey(partitionKeyValue), + cancellationToken: cancellationToken)); + } + + /// + /// + /// + /// + [TestMethod] + [Owner("philipthomas")] + [Description("DeleteItemAsync is yielding a Newtonsoft.Json.JsonSerializationException whenever " + + "the item is not found and MissingMemberHandling is set to MissingMemberHandling.Error. " + + "DeleteItemAsync should yield a CosmosException with a NotFound StatusCode.")] + public async Task GivenDeleteItemAsyncWhenMissingMemberHandlingIsErrorThenExpectsCosmosExceptionTestAsync() + { + await CosmosItemTests.GivenItemAsyncWhenMissingMemberHandlingIsErrorThenExpectsCosmosExceptionTestAsync( + itemAsync: async (container, itemIdThatWillNotExist, partitionKeyValue, toDoActivity, cancellationToken) => await container.DeleteItemAsync( + id: itemIdThatWillNotExist, + partitionKey: new Cosmos.PartitionKey(partitionKeyValue), + cancellationToken: cancellationToken)); + } + + /// + /// + /// + /// + [TestMethod] + [Owner("philipthomas")] + [Description("DeleteItemStreamAsync is yielding a Newtonsoft.Json.JsonSerializationException whenever " + + "the item is not found and the MissingMemberHandling is set to MissingMemberHandling.Error. " + + "DeleteItemStreamAsync should yield a CosmosException with a NotFound StatusCode.")] + public async Task GivenReplaceItemStreamAsyncWhenMissingMemberHandlingIsErrorThenExpectsCosmosExceptionTestAsync() + { + await CosmosItemTests.GivenItemStreamAsyncWhenMissingMemberHandlingIsErrorThenExpectsCosmosExceptionTestAsync( + itemStreamAsync: async (container, itemIdThatWillNotExist, partitionKeyValue, cancellationToken) => await container.ReplaceItemStreamAsync( + streamPayload: new MemoryStream(), + id: itemIdThatWillNotExist, + partitionKey: new Cosmos.PartitionKey(partitionKeyValue), + cancellationToken: cancellationToken)); + } + + /// + /// + /// + /// + [TestMethod] + [Owner("philipthomas")] + [Description("ReplaceItemAsync is yielding a Newtonsoft.Json.JsonSerializationException whenever " + + "the item is not found and MissingMemberHandling is set to MissingMemberHandling.Error. " + + "ReplaceItemAsync should yield a CosmosException with a NotFound StatusCode.")] + public async Task GivenReplaceItemAsyncWhenMissingMemberHandlingIsErrorThenExpectsCosmosExceptionTestAsync() + { + await CosmosItemTests.GivenItemAsyncWhenMissingMemberHandlingIsErrorThenExpectsCosmosExceptionTestAsync( + itemAsync: async (container, itemIdThatWillNotExist, partitionKeyValue, toDoActivity, cancellationToken) => await container.ReplaceItemAsync( + item: toDoActivity, + id: itemIdThatWillNotExist, + partitionKey: new Cosmos.PartitionKey(partitionKeyValue), + cancellationToken: cancellationToken)); + } + + /// + /// + /// + /// + [TestMethod] + [Owner("philipthomas")] + [Description("PatchItemStreamAsync is yielding a Newtonsoft.Json.JsonSerializationException whenever " + + "the item is not found and the MissingMemberHandling is set to MissingMemberHandling.Error. " + + "PatchItemStreamAsync should yield a CosmosException with a NotFound StatusCode.")] + public async Task GivenPatchItemStreamAsyncWhenMissingMemberHandlingIsErrorThenExpectsCosmosExceptionTestAsync() + { + List patchOperations = new() + { + PatchOperation.Add("/children/1/pk", "patched"), + PatchOperation.Remove("/description"), + PatchOperation.Replace("/taskNum", 1) + }; + + await CosmosItemTests.GivenItemStreamAsyncWhenMissingMemberHandlingIsErrorThenExpectsCosmosExceptionTestAsync( + itemStreamAsync: async (container, itemIdThatWillNotExist, partitionKeyValue, cancellationToken) => await container.PatchItemStreamAsync( + patchOperations: patchOperations, + id: itemIdThatWillNotExist, + partitionKey: new Cosmos.PartitionKey(partitionKeyValue), + cancellationToken: cancellationToken)); + } + + /// + /// + /// + /// + [TestMethod] + [Owner("philipthomas")] + [Description("PatchItemAsync is yielding a Newtonsoft.Json.JsonSerializationException whenever " + + "the item is not found and MissingMemberHandling is set to MissingMemberHandling.Error. " + + "PatchItemAsync should yield a CosmosException with a NotFound StatusCode.")] + public async Task GivenPatchItemAsyncWhenMissingMemberHandlingIsErrorThenExpectsCosmosExceptionTestAsync() + { + List patchOperations = new() + { + PatchOperation.Add("/children/1/pk", "patched"), + PatchOperation.Remove("/description"), + PatchOperation.Replace("/taskNum", 1) + }; + + await CosmosItemTests.GivenItemAsyncWhenMissingMemberHandlingIsErrorThenExpectsCosmosExceptionTestAsync( + itemAsync: async (container, itemIdThatWillNotExist, partitionKeyValue, toDoActivity, cancellationToken) => await container.PatchItemAsync( + patchOperations: patchOperations, + id: itemIdThatWillNotExist, + partitionKey: new Cosmos.PartitionKey(partitionKeyValue), + cancellationToken: cancellationToken)); + } + + private static async Task GivenItemStreamAsyncWhenMissingMemberHandlingIsErrorThenExpectsCosmosExceptionTestAsync( + Func> itemStreamAsync) { // AAA // Arrange CancellationTokenSource cancellationTokenSource = new(); CancellationToken cancellationToken = cancellationTokenSource.Token; - int toStreamCount = 0; - int fromStreamCount = 0; - CosmosSerializerHelper serializer = new( - jsonSerializerSettings: new JsonSerializerSettings() + JsonConvert.DefaultSettings = () => new JsonSerializerSettings + { + MissingMemberHandling = MissingMemberHandling.Error + }; + + CosmosClient cosmosClient = TestCommon.CreateCosmosClient(); + + string databaseId = Guid.NewGuid().ToString(); + Cosmos.Database database = await cosmosClient.CreateDatabaseIfNotExistsAsync( + id: databaseId, + cancellationToken: cancellationToken); + + try + { + string containerId = Guid.NewGuid().ToString(); + Container container = await database.CreateContainerIfNotExistsAsync( + containerProperties: new ContainerProperties + { + Id = containerId, + PartitionKeyPath = "/pk", + }, + cancellationToken: cancellationToken); + + + // Act + string itemIdThatWillNotExist = Guid.NewGuid().ToString(); + string partitionKeyValue = Guid.NewGuid().ToString(); + + ResponseMessage response = await itemStreamAsync(container, itemIdThatWillNotExist, partitionKeyValue, cancellationToken); + + // Assert + Debug.Assert( + condition: response != null, + message: $"{response}"); + + Assert.AreEqual( + expected: HttpStatusCode.NotFound, + actual: response.StatusCode); + + string content = JsonConvert.SerializeObject(response.Content); + + Assert.AreEqual( + expected: "null", + actual: content); + + string errorMessage = JsonConvert.SerializeObject(response.ErrorMessage); + + Assert.IsNotNull(value: errorMessage); + + Debug.Assert( + condition: response.CosmosException != null, + message: $"{response.CosmosException}"); + + Assert.AreEqual( + expected: HttpStatusCode.NotFound, + actual: response.StatusCode); + + Debug.WriteLine(message: $"{nameof(response.CosmosException)}: {response.CosmosException}"); + + Assert.AreEqual( + actual: response.CosmosException.StatusCode, + expected: HttpStatusCode.NotFound); + } + catch (JsonSerializationException jsonSerializationException) + { + Assert.Fail(message: $"JsonSerializationException was caught, so fail the test. {jsonSerializationException}."); + } + catch (Exception otherException) + { + Assert.Fail(message: $"Any other exception is thrown before the Act, so fail the test. {otherException}."); + } + finally + { + if (database != null) { - NullValueHandling = NullValueHandling.Ignore, - MissingMemberHandling = MissingMemberHandling.Error, - }, - fromStreamCallback: item => fromStreamCount++, - toStreamCallBack: item => toStreamCount++); + // Remove the test database. Cleanup. + _ = await database.DeleteAsync(cancellationToken: cancellationToken); - CosmosClient cosmosClient = TestCommon.CreateCosmosClient(customizeClientBuilder: builder => builder.WithCustomSerializer(cosmosJsonSerializer: serializer)); + Debug.WriteLine($"The {nameof(database)} with id '{databaseId}' was removed."); + } + } + } + + private static async Task GivenItemAsyncWhenMissingMemberHandlingIsErrorThenExpectsCosmosExceptionTestAsync( + Func>> itemAsync) + { + // AAA + // Arrange + CancellationTokenSource cancellationTokenSource = new(); + CancellationToken cancellationToken = cancellationTokenSource.Token; + + JsonConvert.DefaultSettings = () => new JsonSerializerSettings + { + MissingMemberHandling = MissingMemberHandling.Error + }; + + CosmosClient cosmosClient = TestCommon.CreateCosmosClient(); string databaseId = Guid.NewGuid().ToString(); Cosmos.Database database = await cosmosClient.CreateDatabaseIfNotExistsAsync( @@ -3200,20 +3439,18 @@ public async Task GivenReadItemAsyncSerializationExceptionWhenMissingMemberHandl // Act // If any thing other than a CosmosException is thrown, the call to ReadItemAsync below will fail. string itemIdThatWillNotExist = Guid.NewGuid().ToString(); - string partitionKeyValue = "Washington"; + string partitionKeyValue = Guid.NewGuid().ToString(); + CosmosException cosmosException = await Assert.ThrowsExceptionAsync(action: - async () => await container.ReadItemAsync( - id: itemIdThatWillNotExist, - partitionKey: new Cosmos.PartitionKey(partitionKeyValue), - cancellationToken: cancellationToken)); - + async () => await itemAsync(container, itemIdThatWillNotExist, partitionKeyValue, new ToDoActivity { id = Guid.NewGuid().ToString(), pk = "Georgia" }, cancellationToken)) ; + + // Assert Debug.Assert( condition: cosmosException != null, message: $"{cosmosException}"); Debug.WriteLine(message: $"{nameof(cosmosException)}: {cosmosException}"); - // Assert Assert.AreEqual( actual: cosmosException.StatusCode, expected: HttpStatusCode.NotFound); From e06da21d347411ffe19612e1c339fe28bafc8cd9 Mon Sep 17 00:00:00 2001 From: philipthomas Date: Tue, 17 Oct 2023 11:43:38 -0400 Subject: [PATCH 3/5] commit on some actionables --- .../CosmosItemTests.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) 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 4a79beb4c8..19290ff1b1 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs @@ -3321,6 +3321,13 @@ private static async Task GivenItemStreamAsyncWhenMissingMemberHandlingIsErrorTh CancellationTokenSource cancellationTokenSource = new(); CancellationToken cancellationToken = cancellationTokenSource.Token; + // Food for thought, actionable items. + // + // 1. Is there anything else that we should be concerned with that would give us the same behavior? + // 2. Are there other operations other than those that can yield an NotFound exception that we should be + // concerned with? + // 3. Can we also reset the DefaultSettings before we make the call, and reset it back once it is done? + JsonConvert.DefaultSettings = () => new JsonSerializerSettings { MissingMemberHandling = MissingMemberHandling.Error @@ -3412,6 +3419,13 @@ private static async Task GivenItemAsyncWhenMissingMemberHandlingIsErrorThenExpe CancellationTokenSource cancellationTokenSource = new(); CancellationToken cancellationToken = cancellationTokenSource.Token; + // Food for thought, actionable items. + // + // 1. Is there anything else that we should be concerned with that would give us the same behavior? + // 2. Are there other operations other than those that can yield an NotFound exception that we should be + // concerned with? + // 3. Can we also reset the DefaultSettings before we make the call, and reset it back once it is done? + JsonConvert.DefaultSettings = () => new JsonSerializerSettings { MissingMemberHandling = MissingMemberHandling.Error From 6192173d2c50b2f1266a6d01283d42d14f1060f7 Mon Sep 17 00:00:00 2001 From: philipthomas Date: Wed, 18 Oct 2023 08:39:54 -0400 Subject: [PATCH 4/5] setting JsonConvert.DefaultSettings to null so that other tests will not fail --- .../CosmosItemTests.cs | 8 ++++++++ 1 file changed, 8 insertions(+) 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 19290ff1b1..7c9055387b 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs @@ -3408,6 +3408,10 @@ private static async Task GivenItemStreamAsyncWhenMissingMemberHandlingIsErrorTh Debug.WriteLine($"The {nameof(database)} with id '{databaseId}' was removed."); } + + // Setting this back because it blows up other serialization tests. + + JsonConvert.DefaultSettings = () => default; } } @@ -3486,6 +3490,10 @@ private static async Task GivenItemAsyncWhenMissingMemberHandlingIsErrorThenExpe Debug.WriteLine($"The {nameof(database)} with id '{databaseId}' was removed."); } + + // Setting this back because it blows up other serialization tests. + + JsonConvert.DefaultSettings = () => default; } } From 1bed577bbbbb653fd39557b68deee0d67fada27e Mon Sep 17 00:00:00 2001 From: philipthomas Date: Wed, 18 Oct 2023 12:03:10 -0400 Subject: [PATCH 5/5] as requested, removed catches from test methods --- .../CosmosItemTests.cs | 16 ---------------- 1 file changed, 16 deletions(-) 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 7c9055387b..860c780e41 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs @@ -3391,14 +3391,6 @@ private static async Task GivenItemStreamAsyncWhenMissingMemberHandlingIsErrorTh actual: response.CosmosException.StatusCode, expected: HttpStatusCode.NotFound); } - catch (JsonSerializationException jsonSerializationException) - { - Assert.Fail(message: $"JsonSerializationException was caught, so fail the test. {jsonSerializationException}."); - } - catch (Exception otherException) - { - Assert.Fail(message: $"Any other exception is thrown before the Act, so fail the test. {otherException}."); - } finally { if (database != null) @@ -3473,14 +3465,6 @@ private static async Task GivenItemAsyncWhenMissingMemberHandlingIsErrorThenExpe actual: cosmosException.StatusCode, expected: HttpStatusCode.NotFound); } - catch (JsonSerializationException jsonSerializationException) - { - Assert.Fail(message: $"JsonSerializationException was caught, so fail the test. {jsonSerializationException}."); - } - catch (Exception otherException) - { - Assert.Fail(message: $"Any other exception is thrown before the Act, so fail the test. {otherException}."); - } finally { if (database != null)