提交 5b43c092 编写于 作者: S Sam Harwell

Move test helpers to test accessors

上级 f244a937
......@@ -159,20 +159,35 @@ public void WaitForPendingBackgroundWork()
_currentBackgroundTask.Wait();
}
/// <summary>
/// Wait until all tasks have been completed. NOTE that this will do a pumping wait if
/// called on the UI thread. Also, it isn't guaranteed to be stable in the case of tasks
/// enqueuing other tasks in arbitrary orders, though it does support our common pattern of
/// "timer task->background task->foreground task with results"
///
/// Use this method very judiciously. Most of the time, we should be able to just use
/// IAsynchronousOperationListener for tests.
/// </summary>
public void WaitUntilCompletion_ForTestingPurposesOnly()
internal TestAccessor GetTestAccessor()
{
AssertIsForeground();
return new TestAccessor(this);
}
internal readonly struct TestAccessor
{
private readonly AsynchronousSerialWorkQueue _asynchronousSerialWorkQueue;
WaitForPendingBackgroundWork();
internal TestAccessor(AsynchronousSerialWorkQueue asynchronousSerialWorkQueue)
{
_asynchronousSerialWorkQueue = asynchronousSerialWorkQueue;
}
/// <summary>
/// Wait until all tasks have been completed. NOTE that this will do a pumping wait if
/// called on the UI thread. Also, it isn't guaranteed to be stable in the case of tasks
/// enqueuing other tasks in arbitrary orders, though it does support our common pattern of
/// "timer task->background task->foreground task with results"
///
/// Use this method very judiciously. Most of the time, we should be able to just use
/// IAsynchronousOperationListener for tests.
/// </summary>
public void WaitUntilCompletion()
{
_asynchronousSerialWorkQueue.AssertIsForeground();
_asynchronousSerialWorkQueue.WaitForPendingBackgroundWork();
}
}
}
}
......@@ -1315,7 +1315,7 @@ private static async Task WaitAsync(SolutionCrawlerRegistrationService service,
{
await WaitWaiterAsync(workspace.ExportProvider);
service.WaitUntilCompletion_ForTestingPurposesOnly(workspace);
service.GetTestAccessor().WaitUntilCompletion(workspace);
}
private static async Task WaitWaiterAsync(ExportProvider provider)
......
......@@ -246,7 +246,7 @@ public void TestBackgroundCancelMultipleActions()
try
{
worker.WaitUntilCompletion_ForTestingPurposesOnly();
worker.GetTestAccessor().WaitUntilCompletion();
Assert.True(false);
}
catch (AggregateException ae)
......
......@@ -404,7 +404,7 @@ End Namespace
Dim provider = DirectCast(workspace.ExportProvider.GetExports(Of IWorkspaceServiceFactory).First(
Function(f) TypeOf f.Value Is SymbolTreeInfoIncrementalAnalyzerProvider).Value, SymbolTreeInfoIncrementalAnalyzerProvider)
Dim analyzer = provider.CreateIncrementalAnalyzer(workspace)
solutionCrawler.WaitUntilCompletion_ForTestingPurposesOnly(workspace, ImmutableArray.Create(analyzer))
solutionCrawler.GetTestAccessor().WaitUntilCompletion(workspace, ImmutableArray.Create(analyzer))
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddImport)>
......
......@@ -323,7 +323,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests
' CollectErrors generates interleaved background and foreground tasks.
Dim service = DirectCast(workspace.Services.GetService(Of ISolutionCrawlerRegistrationService)(), SolutionCrawlerRegistrationService)
service.WaitUntilCompletion_ForTestingPurposesOnly(workspace, SpecializedCollections.SingletonEnumerable(analyzerService.CreateIncrementalAnalyzer(workspace)).WhereNotNull().ToImmutableArray())
service.GetTestAccessor().WaitUntilCompletion(workspace, SpecializedCollections.SingletonEnumerable(analyzerService.CreateIncrementalAnalyzer(workspace)).WhereNotNull().ToImmutableArray())
Return analyzerService
End Function
......
......@@ -105,7 +105,7 @@ public async Task WaitForTags()
{
if (_solutionCrawlerService != null)
{
_solutionCrawlerService.WaitUntilCompletion_ForTestingPurposesOnly(_workspace, _incrementalAnalyzers);
_solutionCrawlerService.GetTestAccessor().WaitUntilCompletion(_workspace, _incrementalAnalyzers);
}
await _listenerProvider.GetWaiter(FeatureAttribute.DiagnosticService).ExpeditedWaitAsync();
......
......@@ -165,22 +165,6 @@ public void Reanalyze(Workspace workspace, IIncrementalAnalyzer analyzer, IEnume
}
}
internal void WaitUntilCompletion_ForTestingPurposesOnly(Workspace workspace, ImmutableArray<IIncrementalAnalyzer> workers)
{
if (_documentWorkCoordinatorMap.TryGetValue(workspace, out var coordinator))
{
coordinator.WaitUntilCompletion_ForTestingPurposesOnly(workers);
}
}
internal void WaitUntilCompletion_ForTestingPurposesOnly(Workspace workspace)
{
if (_documentWorkCoordinatorMap.TryGetValue(workspace, out var coordinator))
{
coordinator.WaitUntilCompletion_ForTestingPurposesOnly();
}
}
private IEnumerable<Lazy<IIncrementalAnalyzerProvider, IncrementalAnalyzerProviderMetadata>> GetAnalyzerProviders(string workspaceKind)
{
foreach (var (_, lazyProviders) in _analyzerProviders)
......@@ -269,6 +253,45 @@ internal void WaitUntilCompletion_ForTestingPurposesOnly(Workspace workspace)
private static bool IsDefaultProvider(IncrementalAnalyzerProviderMetadata providerMetadata)
=> providerMetadata.WorkspaceKinds == null || providerMetadata.WorkspaceKinds.Count == 0;
internal TestAccessor GetTestAccessor()
{
return new TestAccessor(this);
}
internal readonly struct TestAccessor
{
private readonly SolutionCrawlerRegistrationService _solutionCrawlerRegistrationService;
internal TestAccessor(SolutionCrawlerRegistrationService solutionCrawlerRegistrationService)
{
_solutionCrawlerRegistrationService = solutionCrawlerRegistrationService;
}
private bool TryGetWorkCoordinator(Workspace workspace, [NotNullWhen(true)] out WorkCoordinator? coordinator)
{
lock (_solutionCrawlerRegistrationService._gate)
{
return _solutionCrawlerRegistrationService._documentWorkCoordinatorMap.TryGetValue(workspace, out coordinator);
}
}
internal void WaitUntilCompletion(Workspace workspace, ImmutableArray<IIncrementalAnalyzer> workers)
{
if (TryGetWorkCoordinator(workspace, out var coordinator))
{
coordinator.GetTestAccessor().WaitUntilCompletion(workers);
}
}
internal void WaitUntilCompletion(Workspace workspace)
{
if (TryGetWorkCoordinator(workspace, out var coordinator))
{
coordinator.GetTestAccessor().WaitUntilCompletion();
}
}
}
private class Registration
{
public readonly int CorrelationId;
......
......@@ -407,18 +407,33 @@ private static bool CrashUnlessCanceled(AggregateException aggregate)
return false;
}
internal void WaitUntilCompletion_ForTestingPurposesOnly(ImmutableArray<IIncrementalAnalyzer> analyzers, List<WorkItem> items)
internal TestAccessor GetTestAccessor()
{
_normalPriorityProcessor.WaitUntilCompletion_ForTestingPurposesOnly(analyzers, items);
var projectItems = items.Select(i => i.ToProjectWorkItem(EmptyAsyncToken.Instance));
_lowPriorityProcessor.WaitUntilCompletion_ForTestingPurposesOnly(analyzers, items);
return new TestAccessor(this);
}
internal void WaitUntilCompletion_ForTestingPurposesOnly()
internal readonly struct TestAccessor
{
_normalPriorityProcessor.WaitUntilCompletion_ForTestingPurposesOnly();
_lowPriorityProcessor.WaitUntilCompletion_ForTestingPurposesOnly();
private readonly IncrementalAnalyzerProcessor _incrementalAnalyzerProcessor;
internal TestAccessor(IncrementalAnalyzerProcessor incrementalAnalyzerProcessor)
{
_incrementalAnalyzerProcessor = incrementalAnalyzerProcessor;
}
internal void WaitUntilCompletion(ImmutableArray<IIncrementalAnalyzer> analyzers, List<WorkItem> items)
{
_incrementalAnalyzerProcessor._normalPriorityProcessor.GetTestAccessor().WaitUntilCompletion(analyzers, items);
var projectItems = items.Select(i => i.ToProjectWorkItem(EmptyAsyncToken.Instance));
_incrementalAnalyzerProcessor._lowPriorityProcessor.GetTestAccessor().WaitUntilCompletion(analyzers, items);
}
internal void WaitUntilCompletion()
{
_incrementalAnalyzerProcessor._normalPriorityProcessor.GetTestAccessor().WaitUntilCompletion();
_incrementalAnalyzerProcessor._lowPriorityProcessor.GetTestAccessor().WaitUntilCompletion();
}
}
private class NullDisposable : IDisposable
......
......@@ -195,24 +195,39 @@ public override void Shutdown()
_workItemQueue.Dispose();
}
internal void WaitUntilCompletion_ForTestingPurposesOnly(ImmutableArray<IIncrementalAnalyzer> analyzers, List<WorkItem> items)
internal TestAccessor GetTestAccessor()
{
var uniqueIds = new HashSet<ProjectId>();
foreach (var item in items)
return new TestAccessor(this);
}
internal readonly struct TestAccessor
{
private readonly LowPriorityProcessor _lowPriorityProcessor;
internal TestAccessor(LowPriorityProcessor lowPriorityProcessor)
{
_lowPriorityProcessor = lowPriorityProcessor;
}
internal void WaitUntilCompletion(ImmutableArray<IIncrementalAnalyzer> analyzers, List<WorkItem> items)
{
if (uniqueIds.Add(item.ProjectId))
var uniqueIds = new HashSet<ProjectId>();
foreach (var item in items)
{
ProcessProjectAsync(analyzers, item, CancellationToken.None).Wait();
if (uniqueIds.Add(item.ProjectId))
{
_lowPriorityProcessor.ProcessProjectAsync(analyzers, item, CancellationToken.None).Wait();
}
}
}
}
internal void WaitUntilCompletion_ForTestingPurposesOnly()
{
// this shouldn't happen. would like to get some diagnostic
while (_workItemQueue.HasAnyWork)
internal void WaitUntilCompletion()
{
FailFast.Fail("How?");
// this shouldn't happen. would like to get some diagnostic
while (_lowPriorityProcessor._workItemQueue.HasAnyWork)
{
FailFast.Fail("How?");
}
}
}
}
......
......@@ -587,20 +587,35 @@ public override void Shutdown()
_projectCache = null;
}
internal void WaitUntilCompletion_ForTestingPurposesOnly(ImmutableArray<IIncrementalAnalyzer> analyzers, List<WorkItem> items)
internal TestAccessor GetTestAccessor()
{
foreach (var item in items)
{
ProcessDocumentAsync(analyzers, item, CancellationToken.None).Wait();
}
return new TestAccessor(this);
}
internal void WaitUntilCompletion_ForTestingPurposesOnly()
internal readonly struct TestAccessor
{
// this shouldn't happen. would like to get some diagnostic
while (_workItemQueue.HasAnyWork)
private readonly NormalPriorityProcessor _normalPriorityProcessor;
internal TestAccessor(NormalPriorityProcessor normalPriorityProcessor)
{
FailFast.Fail("How?");
_normalPriorityProcessor = normalPriorityProcessor;
}
internal void WaitUntilCompletion(ImmutableArray<IIncrementalAnalyzer> analyzers, List<WorkItem> items)
{
foreach (var item in items)
{
_normalPriorityProcessor.ProcessDocumentAsync(analyzers, item, CancellationToken.None).Wait();
}
}
internal void WaitUntilCompletion()
{
// this shouldn't happen. would like to get some diagnostic
while (_normalPriorityProcessor._workItemQueue.HasAnyWork)
{
FailFast.Fail("How?");
}
}
}
}
......
......@@ -662,24 +662,39 @@ private async Task EnqueueWorkItemAfterDiffAsync(Solution oldSolution, Solution
await EnqueueWorkItemAsync(oldProject.GetRequiredDocument(documentId), newProject.GetRequiredDocument(documentId)).ConfigureAwait(continueOnCapturedContext: false);
}
internal void WaitUntilCompletion_ForTestingPurposesOnly(ImmutableArray<IIncrementalAnalyzer> workers)
internal TestAccessor GetTestAccessor()
{
var solution = _registration.CurrentSolution;
var list = new List<WorkItem>();
return new TestAccessor(this);
}
internal readonly struct TestAccessor
{
private readonly WorkCoordinator _workCoordinator;
internal TestAccessor(WorkCoordinator workCoordinator)
{
_workCoordinator = workCoordinator;
}
foreach (var project in solution.Projects)
internal void WaitUntilCompletion(ImmutableArray<IIncrementalAnalyzer> workers)
{
foreach (var document in project.Documents)
var solution = _workCoordinator._registration.CurrentSolution;
var list = new List<WorkItem>();
foreach (var project in solution.Projects)
{
list.Add(new WorkItem(document.Id, document.Project.Language, InvocationReasons.DocumentAdded, isLowPriority: false, activeMember: null, EmptyAsyncToken.Instance));
foreach (var document in project.Documents)
{
list.Add(new WorkItem(document.Id, document.Project.Language, InvocationReasons.DocumentAdded, isLowPriority: false, activeMember: null, EmptyAsyncToken.Instance));
}
}
_workCoordinator._documentAndProjectWorkerProcessor.GetTestAccessor().WaitUntilCompletion(workers, list);
}
_documentAndProjectWorkerProcessor.WaitUntilCompletion_ForTestingPurposesOnly(workers, list);
internal void WaitUntilCompletion()
=> _workCoordinator._documentAndProjectWorkerProcessor.GetTestAccessor().WaitUntilCompletion();
}
internal void WaitUntilCompletion_ForTestingPurposesOnly()
=> _documentAndProjectWorkerProcessor.WaitUntilCompletion_ForTestingPurposesOnly();
}
private readonly struct ReanalyzeScope
......
......@@ -5,6 +5,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>netcoreapp3.1;net472</TargetFrameworks>
<IsShipping>false</IsShipping>
<PlatformTarget>AnyCPU</PlatformTarget>
<ServerGarbageCollection>true</ServerGarbageCollection>
<!-- https://github.com/dotnet/runtime/issues/1713 -->
......
......@@ -68,7 +68,7 @@ public async Task RunAsync(CancellationToken cancellationToken)
incrementalAnalyzerProvider ??= incrementalAnalyzerProviders.Where(x => x.Metadata.Name == incrementalAnalyzerName).SingleOrDefault(provider => provider.Metadata.WorkspaceKinds?.Contains(WorkspaceKind.RemoteWorkspace) ?? false)?.Value;
incrementalAnalyzerProvider ??= incrementalAnalyzerProviders.Where(x => x.Metadata.Name == incrementalAnalyzerName).Single(provider => provider.Metadata.WorkspaceKinds is null).Value;
var incrementalAnalyzer = incrementalAnalyzerProvider.CreateIncrementalAnalyzer(_workspace);
solutionCrawlerRegistrationService.WaitUntilCompletion_ForTestingPurposesOnly(_workspace, ImmutableArray.Create(incrementalAnalyzer));
solutionCrawlerRegistrationService.GetTestAccessor().WaitUntilCompletion(_workspace, ImmutableArray.Create(incrementalAnalyzer));
switch (incrementalAnalyzerName)
{
......
......@@ -783,7 +783,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics
Dim service = DirectCast(workspace.Services.GetService(Of ISolutionCrawlerRegistrationService)(), SolutionCrawlerRegistrationService)
service.Register(workspace)
service.WaitUntilCompletion_ForTestingPurposesOnly(workspace, SpecializedCollections.SingletonEnumerable(analyzerService.CreateIncrementalAnalyzer(workspace)).WhereNotNull().ToImmutableArray())
service.GetTestAccessor().WaitUntilCompletion(workspace, SpecializedCollections.SingletonEnumerable(analyzerService.CreateIncrementalAnalyzer(workspace)).WhereNotNull().ToImmutableArray())
End Sub
Private Function CreateItem(documentId As DocumentId, Optional severity As DiagnosticSeverity = DiagnosticSeverity.Error) As DiagnosticData
......
......@@ -181,14 +181,6 @@ public void WriteTo(ObjectWriter writer)
}
}
internal static SymbolTreeInfo ReadSymbolTreeInfo_ForTestingPurposesOnly(
ObjectReader reader, Checksum checksum)
{
return TryReadSymbolTreeInfo(reader, checksum,
(names, nodes) => Task.FromResult(
new SpellChecker(checksum, nodes.Select(n => new StringSlice(names, n.NameSpan)))));
}
private static SymbolTreeInfo TryReadSymbolTreeInfo(
ObjectReader reader,
Checksum checksum,
......@@ -262,5 +254,16 @@ public void WriteTo(ObjectWriter writer)
return null;
}
internal readonly partial struct TestAccessor
{
internal static SymbolTreeInfo ReadSymbolTreeInfo(
ObjectReader reader, Checksum checksum)
{
return TryReadSymbolTreeInfo(reader, checksum,
(names, nodes) => Task.FromResult(
new SpellChecker(checksum, nodes.Select(n => new StringSlice(names, n.NameSpan)))));
}
}
}
}
......@@ -685,8 +685,7 @@ public async Task TestSymbolTreeInfoSerialization()
using var readerStream = new MemoryStream(writerStream.ToArray());
using var reader = ObjectReader.TryGetReader(readerStream);
var readInfo = SymbolTreeInfo.ReadSymbolTreeInfo_ForTestingPurposesOnly(
reader, Checksum.Null);
var readInfo = SymbolTreeInfo.TestAccessor.ReadSymbolTreeInfo(reader, Checksum.Null);
info.AssertEquivalentTo(readInfo);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册