提交 2142495e 编写于 作者: J Jared Parsons

Fix EditorFeatures2 flakiness

The EditorFeatures2 flakiness was being caused by two separate issues.
The first underlying problem is a simple bug in async completion. This
issue is being tracked by the VS editor team here

https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1091056

The second issue is how the Roslyn test framework handles unexpected
extension exceptions. It was using a `FailFast` call when this happened
vs. using `Assert.Fail` or similar. The reason being that at the point
the unexpected exception is detected using `Assert.Fail` isn't effective
because the editor is going to catch and swallow all exceptions. The
`FailFast` is the only way to guarantee that the test will fail.

The downside to `FailFast` though is that it doesn't produce actionable
information. The xUnit process will simply exit with no stack trace,
failure message, etc .... just a fail fast error code. This makes
failures like this incredibly hard to track down.

To fix this the `TestExtensionErrorHandler` will now store the
unexpected `Exception` object and the containing workspace will look for
it and fail the test in `Dispose`. This will reliably fail the tests
that use `TestWorkspace` in this manner.

closes #42586
上级 6f2eadab
...@@ -14,10 +14,13 @@ ...@@ -14,10 +14,13 @@
namespace Microsoft.CodeAnalysis.Editor.UnitTests namespace Microsoft.CodeAnalysis.Editor.UnitTests
{ {
[Export(typeof(IExtensionErrorHandler))] [Export(typeof(IExtensionErrorHandler))]
[Export(typeof(TestExtensionErrorHandler))]
internal class TestExtensionErrorHandler : IExtensionErrorHandler internal class TestExtensionErrorHandler : IExtensionErrorHandler
{ {
private ImmutableList<Exception> _exceptions = ImmutableList<Exception>.Empty; private ImmutableList<Exception> _exceptions = ImmutableList<Exception>.Empty;
public ImmutableList<Exception> Exceptions => _exceptions;
[ImportingConstructor] [ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public TestExtensionErrorHandler() public TestExtensionErrorHandler()
...@@ -27,12 +30,24 @@ public TestExtensionErrorHandler() ...@@ -27,12 +30,24 @@ public TestExtensionErrorHandler()
public void HandleError(object sender, Exception exception) public void HandleError(object sender, Exception exception)
{ {
// Work around bug that is fixed in https://devdiv.visualstudio.com/DevDiv/_git/VS-Platform/pullrequest/209513 // Work around bug that is fixed in https://devdiv.visualstudio.com/DevDiv/_git/VS-Platform/pullrequest/209513
if (exception is NullReferenceException && exception.StackTrace.Contains("SpanTrackingWpfToolTipPresenter")) if (exception is NullReferenceException &&
exception.StackTrace.Contains("SpanTrackingWpfToolTipPresenter"))
{
return;
}
// Work around for https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1091056
if (exception is InvalidOperationException &&
exception.StackTrace.Contains("Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Implementation.CompletionTelemetryHost"))
{ {
return; return;
} }
ExceptionUtilities.FailFast(exception); // This exception is unexpected and as such we want the containing test case to
// fail. Unfortuntately throwing an exception here is not going to help because
// the editor is going to catch and swallow it. Store it here and wait for the
// containing workspace to notice it and throw.
_exceptions = _exceptions.Add(exception);
} }
} }
} }
...@@ -48,6 +48,7 @@ public partial class TestWorkspace : Workspace ...@@ -48,6 +48,7 @@ public partial class TestWorkspace : Workspace
private readonly BackgroundCompiler _backgroundCompiler; private readonly BackgroundCompiler _backgroundCompiler;
private readonly BackgroundParser _backgroundParser; private readonly BackgroundParser _backgroundParser;
private readonly IMetadataAsSourceFileService _metadataAsSourceFileService; private readonly IMetadataAsSourceFileService _metadataAsSourceFileService;
private readonly TestExtensionErrorHandler _testExtensionErrorHandler;
private readonly Dictionary<string, ITextBuffer> _createdTextBuffers = new Dictionary<string, ITextBuffer>(); private readonly Dictionary<string, ITextBuffer> _createdTextBuffers = new Dictionary<string, ITextBuffer>();
...@@ -75,6 +76,7 @@ public TestWorkspace(ExportProvider exportProvider, string? workspaceKind = null ...@@ -75,6 +76,7 @@ public TestWorkspace(ExportProvider exportProvider, string? workspaceKind = null
_backgroundParser.Start(); _backgroundParser.Start();
_metadataAsSourceFileService = exportProvider.GetExportedValues<IMetadataAsSourceFileService>().FirstOrDefault(); _metadataAsSourceFileService = exportProvider.GetExportedValues<IMetadataAsSourceFileService>().FirstOrDefault();
_testExtensionErrorHandler = exportProvider.GetExportedValue<TestExtensionErrorHandler>();
RegisterDocumentOptionProviders(exportProvider.GetExports<IDocumentOptionsProviderFactory, OrderableMetadata>()); RegisterDocumentOptionProviders(exportProvider.GetExports<IDocumentOptionsProviderFactory, OrderableMetadata>());
} }
...@@ -142,6 +144,12 @@ protected override void Dispose(bool finalize) ...@@ -142,6 +144,12 @@ protected override void Dispose(bool finalize)
_backgroundParser.CancelAllParses(); _backgroundParser.CancelAllParses();
} }
var exceptions = _testExtensionErrorHandler.Exceptions;
if (exceptions.Count > 0)
{
throw new AggregateException("Extensions threw unexpected exceptions", exceptions);
}
base.Dispose(finalize); base.Dispose(finalize);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册