Repro Test for #3720 (Unobserved Exception)#4460
Conversation
There was a problem hiding this comment.
Pull request overview
Adds unit-test infrastructure and a targeted repro test for issue #3720, demonstrating that exceptions thrown from SniPacket’s async IO completion callback can go unobserved and later surface via TaskScheduler.UnobservedTaskException.
Changes:
- Introduces a shared
ObservableExceptiontest utility to uniquely tag unobserved exceptions. - Refactors
AsyncHelperTestto use the sharedObservableExceptioninstead of an inline nested type. - Adds a new Managed SNI unit test that reliably reproduces the unobserved-exception behavior.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| src/Microsoft.Data.SqlClient/tests/UnitTests/Utilities/ObservableException.cs | Adds a reusable exception type for unobserved-exception testing scenarios. |
| src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/Utilities/AsyncHelperTest.cs | Removes the inline ObservableException in favor of the shared utility type. |
| src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/ManagedSni/SniPacketAsyncCallbackTest.cs | Adds a repro test for unobserved exceptions originating from SniPacket async callbacks. |
paulmedynski
left a comment
There was a problem hiding this comment.
Blocking on Copilot feedback. My suggestion about ObservableException is at your discretion.
| /// Represents a utility exception designed for testing scenarios where exceptions must be observed. | ||
| /// </summary> | ||
| /// <param name="id">Identifier to uniquely identify the </param> | ||
| public ObservableException(Guid id) |
There was a problem hiding this comment.
Should this class generate its own GUID? Not sure it needs one injected, or that it needs a setter:
public class ObservableException : Exception
{
public Guid Identifier { get; } = new();
}
There was a problem hiding this comment.
I guess there is one existing use of this class, but it could be esaily re-arranged to work with the above.
I generally try to avoid providing any unnecessary API surface.
There was a problem hiding this comment.
I have a bit of a grander idea for it ... so I might omit this change for now 😬
There was a problem hiding this comment.
Ok, scope creep time, I turned the structure of the observable exception testing into a disposable helper that takes care of its own setup and cleanup. This also consolidates the flakiness hardening into one spot. The async helper tests have been updated to use this (and as a result the tests take longer, but it is robust to flakiness - within reason).
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/ManagedSni/SniPacketTests.cs:47
- The unobserved-exception filter is currently using
InnerExceptions.Contains(testException), which relies on reference equality. This makes the test more brittle and also diverges from theObservableExceptionremarks and existingAsyncHelperTestpattern (match byIdentifier). Consider matchingObservableException.Identifierinstead (without LINQ, per prior discussion).
EventHandler<UnobservedTaskExceptionEventArgs> handleUnobservedException =
(_, args) =>
{
if (args.Exception.InnerExceptions.Contains(testException))
{
args.SetObserved();
unobservedExceptionRaised.TrySetResult(args.Exception);
}
};
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4460 +/- ##
==========================================
- Coverage 65.83% 64.87% -0.96%
==========================================
Files 287 287
Lines 43763 66958 +23195
==========================================
+ Hits 28812 43440 +14628
- Misses 14951 23518 +8567
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Description
This PR provides a reliable reproduction of #3720 in which an exception produced by the AsyncIOCompletionCallback of the SNI Packet class is not observed, leading to the unobserved exception handler being invoked.
This PR does not attempt to fix the issue, just adds a test that can be used to verify that the behavior exists. Attempts to fix the issue will inherently break this test, but can easily be fixed by changing the single assert in the test from "IsNotNull" to "IsNull".
Issues
#3720
Testing
Ran for hundreds of iterations with no failures observed.