-
Notifications
You must be signed in to change notification settings - Fork 533
Excptionless: Adds enabling exception less for 404/1002, 403, and 400 status codes #5205
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
487b485
Enabling exception less
kirankumarkolli 8ded201
Merge branch 'master' into users/kirankk/enable_exception_less
kirankumarkolli 875c1e8
Fixign the test
kirankumarkolli 15b516c
Merge branch 'users/kirankk/enable_exception_less' of https://github.…
kirankumarkolli 999b63a
Merge branch 'master' into users/kirankk/enable_exception_less
kirankumarkolli b72bfe4
Merge branch 'master' into users/kirankk/enable_exception_less
kirankumarkolli 60fa1ce
Merge branch 'master' into users/kirankk/enable_exception_less
kirankumarkolli 197e200
Adding more troublehsooting context
kirankumarkolli 06c4d0f
Upgrading to direct 3.40.1
kirankumarkolli a437b13
Merge branch 'master' into users/kirankk/enable_exception_less
kirankumarkolli 1ba61fc
Merge branch 'master' into users/kirankk/enable_exception_less
kirankumarkolli 002658a
Clean up merge conflicts: revert Directory.Build.props and CosmosItem…
Copilot 49fd90a
[WIP] Add enabling exception less for 404 and 403 (#5559)
Copilot 4a41df9
Merge branch 'master' into users/kirankk/enable_exception_less
kirankumarkolli 405bef6
Fixing the test
kirankumarkolli fc4f6dd
Add internal repository reference to ExceptionLessTests documentation…
Copilot 2d0af85
Enable exception-less execution for 404/1002, 403, and 400 status cod…
Copilot 547677d
Merge branch 'master' into users/kirankk/enable_exception_less
kirankumarkolli d695880
Merge branch 'master' into users/kirankk/enable_exception_less
kirankumarkolli File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
181 changes: 181 additions & 0 deletions
181
Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ExceptionLessTests.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,181 @@ | ||
| namespace Microsoft.Azure.Cosmos | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @copilot look into it |
||
| { | ||
| using System; | ||
| using System.Collections.Concurrent; | ||
| using System.Collections.Generic; | ||
| using System.Diagnostics; | ||
| using System.Linq; | ||
| using System.Runtime.ExceptionServices; | ||
| using System.Threading; | ||
| using System.Threading.Tasks; | ||
| using Microsoft.Azure.Cosmos.Core.Trace; | ||
| using Microsoft.Azure.Cosmos.Diagnostics; | ||
| using Microsoft.Azure.Cosmos.SDK.EmulatorTests; | ||
| using Microsoft.Azure.Cosmos.Tracing.TraceData; | ||
| using Microsoft.Azure.Documents; | ||
| using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
|
|
||
| /// <summary> | ||
| /// Tests for exception-less behavior in Cosmos DB operations. | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// Reference: https://msdata.visualstudio.com/CosmosDB/_git/CosmosDB?path=/Product/SDK/.net/Microsoft.Azure.Cosmos.Friends/tests/ExceptionLessTests.cs | ||
| /// </remarks> | ||
| [VisualStudio.TestTools.UnitTesting.TestClass] | ||
| public class ExceptionLessTests | ||
| { | ||
| private readonly ConcurrentBag<Exception> Exceptions = new(); | ||
|
|
||
| #nullable enable | ||
| private void ExceptionCaptureHandler(object? sender, FirstChanceExceptionEventArgs eventArgs) | ||
| #nullable disable | ||
| { | ||
| this.Exceptions.Add(eventArgs.Exception); | ||
| } | ||
|
|
||
| [TestInitialize] | ||
| public void TestInit() | ||
| { | ||
| // Subscribe to the FirstChanceException event | ||
| AppDomain.CurrentDomain.FirstChanceException += this.ExceptionCaptureHandler; | ||
|
|
||
| TraceSource traceSource = (TraceSource)typeof(DefaultTrace).GetProperty("TraceSource").GetValue(null); | ||
| traceSource.Switch.Level = SourceLevels.All; | ||
| traceSource.Listeners.Clear(); | ||
| traceSource.Listeners.Add(new ConsoleTraceListener()); | ||
| } | ||
|
|
||
| [TestCleanup] | ||
| public void TestCleanup() | ||
| { | ||
| // Subscribe to the FirstChanceException event | ||
| AppDomain.CurrentDomain.FirstChanceException -= this.ExceptionCaptureHandler; | ||
| this.Exceptions.Clear(); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Test for exception less behavior with session not found scenarios | ||
| /// </summary> | ||
| [TestMethod] | ||
| [Owner("kirankk")] | ||
| [DataRow(ConnectionMode.Gateway, Cosmos.ConsistencyLevel.Session)] | ||
| [DataRow(ConnectionMode.Direct, Cosmos.ConsistencyLevel.Session)] | ||
| public async Task SessionNotFoundTestAsync(ConnectionMode mode, | ||
| Cosmos.ConsistencyLevel consistencyLevel) | ||
| { | ||
| string databaseId = Guid.NewGuid().ToString(); | ||
| string containerId = Guid.NewGuid().ToString(); | ||
|
|
||
| CosmosClientOptions clientOptions = new CosmosClientOptions() | ||
| { | ||
| ConnectionMode = mode, | ||
| RequestTimeout = TimeSpan.FromHours(10), | ||
| EnableUpgradeConsistencyToLocalQuorum = true, | ||
| }; | ||
|
|
||
| using (CosmosClient cosmosClient = TestCommon.CreateCosmosClient(clientOptions)) | ||
| { | ||
| await cosmosClient.CreateDatabaseIfNotExistsAsync(databaseId); | ||
| await cosmosClient.GetDatabase(databaseId).CreateContainerIfNotExistsAsync(containerId, "/id"); | ||
|
|
||
| await cosmosClient.InitializeContainersAsync(new List<(string, string)>() { (databaseId, containerId) }, CancellationToken.None); | ||
|
|
||
| Container container = cosmosClient.GetContainer(databaseId, containerId); | ||
| ContainerProperties containerProperties = await container.ReadContainerAsync(); | ||
|
|
||
| TestObj testObj = new TestObj() { id = Guid.NewGuid().ToString() }; | ||
|
|
||
| ItemResponse<TestObj> createRespMsg = await container.CreateItemAsync<TestObj>(testObj, new Cosmos.PartitionKey(testObj.id)); | ||
|
|
||
| DocumentServiceRequest.DefaultUseStatusCodeFor4041002 = false; | ||
|
|
||
| Trace.TraceInformation($"{Environment.NewLine}First Read (may be cold start) (UseStatusCodeFor4041002={DocumentServiceRequest.DefaultUseStatusCodeFor4041002})"); | ||
| ResponseMessage respMsg = await container.ReadItemStreamAsync(testObj.id, new Cosmos.PartitionKey(testObj.id), | ||
| new ItemRequestOptions() { ConsistencyLevel = consistencyLevel }); | ||
| this.TraceResponseMessageAndAssert(respMsg); | ||
|
|
||
| string futureLsn = this.GetFutureLsn(respMsg.Headers.Session); | ||
| Trace.TraceInformation($"{Environment.NewLine}Second ReadFor404-1002 (UseStatusCodeFor4041002={DocumentServiceRequest.DefaultUseStatusCodeFor4041002}): {futureLsn}"); | ||
| respMsg = await container.ReadItemStreamAsync(testObj.id, new Cosmos.PartitionKey(testObj.id), | ||
| new ItemRequestOptions() { SessionToken = futureLsn, ConsistencyLevel = consistencyLevel }); | ||
| SummaryDiagnostics summaryDiagnostics1 = new SummaryDiagnostics(((CosmosTraceDiagnostics)respMsg.Diagnostics).Value); | ||
| this.TraceResponseMessageAndAssert(respMsg); | ||
|
|
||
| Trace.TraceInformation($"{Environment.NewLine}Third Read (rebase if-any) (UseStatusCodeFor4041002={DocumentServiceRequest.DefaultUseStatusCodeFor4041002})"); | ||
| respMsg = await container.ReadItemStreamAsync(testObj.id, new Cosmos.PartitionKey(testObj.id), | ||
| new ItemRequestOptions() { ConsistencyLevel = consistencyLevel }); | ||
| this.TraceResponseMessageAndAssert(respMsg); | ||
|
|
||
| DocumentServiceRequest.DefaultUseStatusCodeFor4041002 = true; | ||
|
|
||
| Trace.TraceInformation($"{Environment.NewLine}ReadFor404-1002 (UseStatusCodeFor4041002={DocumentServiceRequest.DefaultUseStatusCodeFor4041002}): {futureLsn}"); | ||
| respMsg = await container.ReadItemStreamAsync(testObj.id, new Cosmos.PartitionKey(testObj.id), | ||
| new ItemRequestOptions() { SessionToken = futureLsn, ConsistencyLevel = consistencyLevel }); | ||
| SummaryDiagnostics summaryDiagnostics2 = new SummaryDiagnostics(((CosmosTraceDiagnostics)respMsg.Diagnostics).Value); | ||
| this.TraceResponseMessageAndAssert(respMsg, expectedExceptionCount: 0); | ||
|
|
||
| Assert.IsTrue(summaryDiagnostics1.AllRegionsContacted.Value.SetEquals(summaryDiagnostics2.AllRegionsContacted.Value), $"AllRegionsContacted"); | ||
| CollectionAssert.AreEquivalent(summaryDiagnostics1.GatewayRequestsSummary.Value, summaryDiagnostics2.GatewayRequestsSummary.Value, "GatewayRequestsSummary"); | ||
|
|
||
| // Direct #retries are expected to be different (exception vs exceptionless flows) | ||
| if (mode == ConnectionMode.Direct) | ||
| { | ||
| CollectionAssert.AreEquivalent(summaryDiagnostics1.DirectRequestsSummary.Value.Keys, summaryDiagnostics2.DirectRequestsSummary.Value.Keys); | ||
| Assert.AreEqual(1, summaryDiagnostics1.DirectRequestsSummary.Value.Keys.Count); | ||
|
|
||
| (int statusCode, int subStatusCode) = summaryDiagnostics1.DirectRequestsSummary.Value.Keys.First(); | ||
| int exceptionFlowRetryCount = summaryDiagnostics1.DirectRequestsSummary.Value[(statusCode, subStatusCode)]; | ||
| int exceptionLessFlowRetryCount = summaryDiagnostics2.DirectRequestsSummary.Value[(statusCode, subStatusCode)]; | ||
| Assert.IsTrue(exceptionFlowRetryCount == exceptionLessFlowRetryCount | ||
| || (exceptionLessFlowRetryCount > exceptionFlowRetryCount && ((exceptionLessFlowRetryCount - exceptionFlowRetryCount) / exceptionFlowRetryCount * 100) < 10), | ||
| $"DirectRequestsSummary: {string.Join(Environment.NewLine, summaryDiagnostics1.DirectRequestsSummary.Value.Select(e => $"{e.Key} -> {e.Value}"))} {Environment.NewLine} {string.Join(Environment.NewLine, summaryDiagnostics2.DirectRequestsSummary.Value.Select(e => $"{e.Key} -> {e.Value}"))}"); | ||
| } | ||
|
|
||
| // Delete the database | ||
| await cosmosClient.GetDatabase(databaseId).DeleteAsync(); | ||
| } | ||
| } | ||
|
|
||
| private string GetFutureLsn(string sessionTokenStr) | ||
| { | ||
| if (SessionTokenHelper.TryParse(sessionTokenStr, out string partitionKeyRangeId, out ISessionToken parsedSessionToken)) | ||
| { | ||
| VectorSessionToken vectorSessionToken = (VectorSessionToken)parsedSessionToken; | ||
| if (vectorSessionToken != null) | ||
| { | ||
| ISessionToken futureSessionToken = new VectorSessionToken(vectorSessionToken, vectorSessionToken.LSN + 50); | ||
| return $"{partitionKeyRangeId}:{futureSessionToken.ConvertToString()}"; | ||
| } | ||
| } | ||
|
|
||
| throw new ArgumentException($"Failed for {sessionTokenStr}"); | ||
| } | ||
|
|
||
| private void TraceResponseMessageAndAssert(ResponseMessage respMsg, | ||
| int? expectedExceptionCount = null) | ||
| { | ||
| IEnumerable<string> nonHttpExceptions = this.Exceptions.Select(e => e.StackTrace).Where(e => !e.Contains("System.Net.Http.HttpConnection")); | ||
| int currentExceptionCount = nonHttpExceptions.Count(); | ||
| Trace.TraceInformation($"(StatusCode, SubStatusCode): {respMsg.StatusCode} -> {respMsg.Headers.SubStatusCode}"); | ||
| Trace.TraceInformation($"SessionToken(Request -> Response): {respMsg.RequestMessage.Headers.Session} -> {respMsg.Headers.Session}"); | ||
| Trace.TraceInformation($"Exception count: {currentExceptionCount}"); | ||
| Trace.TraceInformation($"Distinct Msg's: {string.Join(Environment.NewLine, this.Exceptions.Select(e => e.Message).GroupBy(e => e, (gpkey, gpValues) => $"{gpkey} -> {gpValues.Count()}"))}"); | ||
| Trace.TraceInformation(respMsg.Diagnostics.ToString()); | ||
|
|
||
| if (expectedExceptionCount.HasValue) | ||
| { | ||
| Assert.AreEqual(expectedExceptionCount, currentExceptionCount, | ||
| $"{string.Join(Environment.NewLine, nonHttpExceptions.Distinct())}"); | ||
| } | ||
|
|
||
| this.Exceptions.Clear(); | ||
| } | ||
|
|
||
| public class TestObj | ||
| { | ||
| #pragma warning disable SA1300 // Element should begin with upper-case letter | ||
| public string id { get; set; } | ||
| #pragma warning restore SA1300 // Element should begin with upper-case letter | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assert.AreEqual failed. Expected:<NotFound (Microsoft.Azure.Documents.StatusCodes)>. Actual:<NotFound (System.Net.HttpStatusCode)>.
Stack Trace:
at Microsoft.Azure.Cosmos.SDK.EmulatorTests.CosmosItemTests.VerifySessionNotFoundStatistics() in D:\a_work\1\s\Microsoft.Azure.Cosmos\tests\Microsoft.Azure.Cosmos.EmulatorTests\CosmosItemTests.cs:line 3402
at Microsoft.Azure.Cosmos.SDK.EmulatorTests.CosmosItemTests.VerifySessionNotFoundStatistics() in D:\a_work\1\s\Microsoft.Azure.Cosmos\tests\Microsoft.Azure.Cosmos.EmulatorTests\CosmosItemTests.cs:line 3412
Change Expected to be actual value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot look into it