public async Task WorkspaceChanged_ProjectChangeEvents_UpdatesProjectState_AfterDelay(WorkspaceChangeKind kind) { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator) { EnqueueDelay = 1, BlockDelayedUpdateWorkEnqueue = new ManualResetEventSlim(initialState: false), }; var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace); projectManager.ProjectAdded(HostProjectOne); var solution = SolutionWithTwoProjects.WithProjectAssemblyName(ProjectNumberOne.Id, "Changed"); var e = new WorkspaceChangeEventArgs(kind, oldSolution: SolutionWithTwoProjects, newSolution: solution, projectId: ProjectNumberOne.Id); // Act detector.Workspace_WorkspaceChanged(Workspace, e); // Assert // // The change hasn't come through yet. Assert.Empty(workspaceStateGenerator.UpdateQueue); detector.BlockDelayedUpdateWorkEnqueue.Set(); await detector._deferredUpdates.Single().Value; var update = Assert.Single(workspaceStateGenerator.UpdateQueue); Assert.Equal(update.workspaceProject.Id, ProjectNumberOne.Id); Assert.Equal(update.projectSnapshot.FilePath, HostProjectOne.FilePath); }
public async Task SolutionClosing_StopsActiveWork() { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher, WorkQueue); WorkQueueTestAccessor.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false); WorkQueueTestAccessor.NotifyBackgroundWorkStarting = new ManualResetEventSlim(initialState: false); Workspace.TryApplyChanges(SolutionWithTwoProjects); var projectManager = new TestProjectSnapshotManager(Dispatcher, new[] { detector }, Workspace); await Dispatcher.RunOnDispatcherThreadAsync(() => projectManager.ProjectAdded(HostProjectOne), CancellationToken.None).ConfigureAwait(false); workspaceStateGenerator.ClearQueue(); WorkQueueTestAccessor.NotifyBackgroundWorkStarting.Wait(); // Act await Dispatcher.RunOnDispatcherThreadAsync(() => { projectManager.SolutionClosed(); // Trigger a project removed event while solution is closing to clear state. projectManager.ProjectRemoved(HostProjectOne); }, CancellationToken.None).ConfigureAwait(false); // Assert // // The change hasn't come through yet. Assert.Empty(workspaceStateGenerator.UpdateQueue); WorkQueueTestAccessor.BlockBackgroundWorkStart.Set(); WorkQueueTestAccessor.NotifyBackgroundWorkCompleted.Wait(); Assert.Empty(workspaceStateGenerator.UpdateQueue); }
public RazorDocumentInfoProviderTest() { var serviceProviderFactory = new DefaultRazorDocumentServiceProviderFactory(); var lspEditorEnabledFeatureDetector = Mock.Of <LSPEditorFeatureDetector>(detector => detector.IsLSPEditorFeatureEnabled() == true, MockBehavior.Strict); InnerDynamicDocumentInfoProvider = new DefaultRazorDynamicFileInfoProvider(serviceProviderFactory, lspEditorEnabledFeatureDetector); ProjectSnapshotManager = new TestProjectSnapshotManager(Workspace); var hostProject = new HostProject("C:/path/to/project.csproj", RazorConfiguration.Default, "RootNamespace"); ProjectSnapshotManager.ProjectAdded(hostProject); var hostDocument = new HostDocument("C:/path/to/document.cshtml", "/C:/path/to/document.cshtml"); var sourceText = SourceText.From("Hello World"); var textAndVersion = TextAndVersion.Create(sourceText, VersionStamp.Default, hostDocument.FilePath); ProjectSnapshotManager.DocumentAdded(hostProject, hostDocument, TextLoader.From(textAndVersion)); ProjectSnapshot = ProjectSnapshotManager.Projects[0]; DocumentSnapshot = ProjectSnapshot.GetDocument(hostDocument.FilePath); var factory = new Mock <VisualStudioMacDocumentInfoFactory>(MockBehavior.Strict); factory.Setup(f => f.CreateEmpty(It.IsAny <string>(), It.IsAny <ProjectId>())) .Returns <string, ProjectId>((razorFilePath, projectId) => { var documentId = DocumentId.CreateNewId(projectId); var documentInfo = DocumentInfo.Create(documentId, "testDoc", filePath: razorFilePath); return(documentInfo); }); Factory = factory.Object; }
public async Task ProcessDocument_SwallowsUnauthorizedAccessExceptions() { // Arrange var projectManager = new TestProjectSnapshotManager(Dispatcher, Workspace); projectManager.ProjectAdded(HostProject1); var textLoader = new Mock <TextLoader>(); textLoader.Setup(loader => loader.LoadTextAndVersionAsync(It.IsAny <Workspace>(), It.IsAny <DocumentId>(), It.IsAny <CancellationToken>())) .Throws <UnauthorizedAccessException>(); projectManager.DocumentAdded(HostProject1, Documents[0], textLoader.Object); var project = projectManager.GetLoadedProject(HostProject1.FilePath); var queue = new BackgroundDocumentGenerator(Dispatcher, DynamicFileInfoProvider, DivergenceChecker) { Delay = TimeSpan.FromMilliseconds(1), NotifyBackgroundWorkCompleted = new ManualResetEventSlim(initialState: false), NotifyErrorBeingReported = new ManualResetEventSlim(initialState: false), }; queue.Initialize(projectManager); // Act & Assert queue.Enqueue(project, project.GetDocument(Documents[0].FilePath)); await Task.Run(() => queue.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3))); Assert.False(queue.NotifyErrorBeingReported.IsSet); }
public DefaultRazorDocumentInfoProviderTest() { ProjectSnapshotManager = new TestProjectSnapshotManager(Workspace); var hostProject = new HostProject("C:/path/to/project.csproj", RazorConfiguration.Default, "RootNamespace"); ProjectSnapshotManager.ProjectAdded(hostProject); var hostDocument = new HostDocument("C:/path/to/document.cshtml", "/C:/path/to/document.cshtml"); var sourceText = SourceText.From("Hello World"); var textAndVersion = TextAndVersion.Create(sourceText, VersionStamp.Default, hostDocument.FilePath); ProjectSnapshotManager.DocumentAdded(hostProject, hostDocument, TextLoader.From(textAndVersion)); ProjectSnapshot = ProjectSnapshotManager.Projects[0]; DocumentSnapshot = ProjectSnapshot.GetDocument(hostDocument.FilePath); var factory = new Mock <VisualStudioMacDocumentInfoFactory>(); factory.Setup(f => f.CreateEmpty(It.IsAny <string>(), It.IsAny <ProjectId>())) .Returns <string, ProjectId>((razorFilePath, projectId) => { var documentId = DocumentId.CreateNewId(projectId); var documentInfo = DocumentInfo.Create(documentId, "testDoc", filePath: razorFilePath); return(documentInfo); }); Factory = factory.Object; }
public async Task WorkspaceChanged_DocumentChanged_Razor_UpdatesProjectState_AfterDelay() { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher, WorkQueue); WorkQueueTestAccessor.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false); Workspace.TryApplyChanges(SolutionWithTwoProjects); var projectManager = new TestProjectSnapshotManager(Dispatcher, new[] { detector }, Workspace); await Dispatcher.RunOnDispatcherThreadAsync(() => projectManager.ProjectAdded(HostProjectOne), CancellationToken.None).ConfigureAwait(false); workspaceStateGenerator.ClearQueue(); var solution = SolutionWithTwoProjects.WithDocumentText(RazorDocumentId, SourceText.From("Hello World")); var e = new WorkspaceChangeEventArgs(WorkspaceChangeKind.DocumentChanged, oldSolution: SolutionWithTwoProjects, newSolution: solution, projectId: ProjectNumberOne.Id, RazorDocumentId); // Act detector.Workspace_WorkspaceChanged(Workspace, e); // Assert // // The change hasn't come through yet. Assert.Empty(workspaceStateGenerator.UpdateQueue); WorkQueueTestAccessor.BlockBackgroundWorkStart.Set(); WorkQueueTestAccessor.NotifyBackgroundWorkCompleted.Wait(); var update = Assert.Single(workspaceStateGenerator.UpdateQueue); Assert.Equal(update.WorkspaceProject.Id, ProjectNumberOne.Id); Assert.Equal(update.ProjectSnapshot.FilePath, HostProjectOne.FilePath); }
public async Task WorkspaceChanged_DocumentChanged_Razor_UpdatesProjectState_AfterDelay() { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator) { EnqueueDelay = 50, }; Workspace.TryApplyChanges(SolutionWithTwoProjects); var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace); projectManager.ProjectAdded(HostProjectOne); workspaceStateGenerator.ClearQueue(); var solution = SolutionWithTwoProjects.WithDocumentText(RazorDocumentId, SourceText.From("Hello World")); var e = new WorkspaceChangeEventArgs(WorkspaceChangeKind.DocumentChanged, oldSolution: SolutionWithTwoProjects, newSolution: solution, projectId: ProjectNumberOne.Id, RazorDocumentId); // Act detector.Workspace_WorkspaceChanged(Workspace, e); // Assert // // The change hasn't come through yet. Assert.Empty(workspaceStateGenerator.UpdateQueue); await detector._deferredUpdates.Single().Value; var update = Assert.Single(workspaceStateGenerator.UpdateQueue); Assert.Equal(update.workspaceProject.Id, ProjectNumberOne.Id); Assert.Equal(update.projectSnapshot.FilePath, HostProjectOne.FilePath); }
public async Task WorkspaceChanged_ProjectEvents_EnqueuesUpdatesForDependentProjects(WorkspaceChangeKind kind) { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher, WorkQueue) { NotifyWorkspaceChangedEventComplete = new ManualResetEventSlim(initialState: false), }; WorkQueueTestAccessor.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false); var projectManager = new TestProjectSnapshotManager(Dispatcher, new[] { detector }, Workspace); await Dispatcher.RunOnDispatcherThreadAsync(() => { projectManager.ProjectAdded(HostProjectOne); projectManager.ProjectAdded(HostProjectTwo); projectManager.ProjectAdded(HostProjectThree); }, CancellationToken.None).ConfigureAwait(false); // Initialize with a project. This will get removed. var e = new WorkspaceChangeEventArgs(WorkspaceChangeKind.SolutionAdded, oldSolution: EmptySolution, newSolution: SolutionWithOneProject); detector.Workspace_WorkspaceChanged(Workspace, e); detector.NotifyWorkspaceChangedEventComplete.Wait(); detector.NotifyWorkspaceChangedEventComplete.Reset(); e = new WorkspaceChangeEventArgs(kind, oldSolution: SolutionWithOneProject, newSolution: SolutionWithDependentProject); var solution = SolutionWithDependentProject.WithProjectAssemblyName(ProjectNumberThree.Id, "Changed"); e = new WorkspaceChangeEventArgs(kind, oldSolution: SolutionWithDependentProject, newSolution: solution, projectId: ProjectNumberThree.Id); // Act detector.Workspace_WorkspaceChanged(Workspace, e); detector.NotifyWorkspaceChangedEventComplete.Wait(); // Assert Assert.Equal(3, WorkQueueTestAccessor.Work.Count); Assert.Contains(WorkQueueTestAccessor.Work, u => u.Key == ProjectNumberOne.FilePath); Assert.Contains(WorkQueueTestAccessor.Work, u => u.Key == ProjectNumberTwo.FilePath); Assert.Contains(WorkQueueTestAccessor.Work, u => u.Key == ProjectNumberThree.FilePath); WorkQueueTestAccessor.BlockBackgroundWorkStart.Set(); WorkQueueTestAccessor.NotifyBackgroundWorkCompleted.Wait(); Assert.Empty(WorkQueueTestAccessor.Work); }
public async Task WorkspaceChanged_SolutionEvents_EnqueuesStateClear_EnqueuesSolutionProjectUpdates(WorkspaceChangeKind kind) { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher, WorkQueue) { NotifyWorkspaceChangedEventComplete = new ManualResetEventSlim(initialState: false), }; var projectManager = new TestProjectSnapshotManager(Dispatcher, new[] { detector }, Workspace); await Dispatcher.RunOnDispatcherThreadAsync(() => { projectManager.ProjectAdded(HostProjectOne); projectManager.ProjectAdded(HostProjectTwo); projectManager.ProjectAdded(HostProjectThree); }, CancellationToken.None).ConfigureAwait(false); // Initialize with a project. This will get removed. var e = new WorkspaceChangeEventArgs(WorkspaceChangeKind.SolutionAdded, oldSolution: EmptySolution, newSolution: SolutionWithOneProject); detector.Workspace_WorkspaceChanged(Workspace, e); detector.NotifyWorkspaceChangedEventComplete.Wait(); detector.NotifyWorkspaceChangedEventComplete.Reset(); WorkQueueTestAccessor.NotifyBackgroundWorkCompleted.Wait(); WorkQueueTestAccessor.NotifyBackgroundWorkCompleted.Reset(); e = new WorkspaceChangeEventArgs(kind, oldSolution: SolutionWithOneProject, newSolution: SolutionWithTwoProjects); // Act detector.Workspace_WorkspaceChanged(Workspace, e); detector.NotifyWorkspaceChangedEventComplete.Wait(); WorkQueueTestAccessor.NotifyBackgroundWorkCompleted.Wait(); // Assert Assert.Collection( workspaceStateGenerator.UpdateQueue, p => Assert.Equal(ProjectNumberThree.Id, p.WorkspaceProject.Id), p => Assert.Null(p.WorkspaceProject), p => Assert.Equal(ProjectNumberOne.Id, p.WorkspaceProject.Id), p => Assert.Equal(ProjectNumberTwo.Id, p.WorkspaceProject.Id)); }
public async Task DocumentRemoved_ReparsesRelatedFiles() { // Arrange var projectManager = new TestProjectSnapshotManager(Dispatcher, Workspace) { AllowNotifyListeners = true, }; projectManager.ProjectAdded(HostProject1); projectManager.DocumentAdded(HostProject1, TestProjectData.SomeProjectComponentFile1, null); projectManager.DocumentAdded(HostProject1, TestProjectData.SomeProjectImportFile, null); var queue = new BackgroundDocumentGenerator(Dispatcher, DynamicFileInfoProvider) { Delay = TimeSpan.FromMilliseconds(1), BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false), NotifyBackgroundWorkStarting = new ManualResetEventSlim(initialState: false), NotifyBackgroundCapturedWorkload = new ManualResetEventSlim(initialState: false), BlockBackgroundWorkCompleting = new ManualResetEventSlim(initialState: false), NotifyBackgroundWorkCompleted = new ManualResetEventSlim(initialState: false), }; queue.Initialize(projectManager); // Act & Assert projectManager.DocumentRemoved(HostProject1, TestProjectData.SomeProjectImportFile); Assert.True(queue.IsScheduledOrRunning, "Queue should be scheduled during Enqueue"); Assert.True(queue.HasPendingNotifications, "Queue should have a notification created during Enqueue"); var kvp = Assert.Single(queue.Work); var expectedKey = new DocumentKey(HostProject1.FilePath, TestProjectData.SomeProjectComponentFile1.FilePath); Assert.Equal(expectedKey, kvp.Key); // Allow the background work to start. queue.BlockBackgroundWorkStart.Set(); await Task.Run(() => queue.NotifyBackgroundWorkStarting.Wait(TimeSpan.FromSeconds(1))); Assert.True(queue.IsScheduledOrRunning, "Worker should be processing now"); await Task.Run(() => queue.NotifyBackgroundCapturedWorkload.Wait(TimeSpan.FromSeconds(1))); Assert.False(queue.HasPendingNotifications, "Worker should have taken all notifications"); // Allow work to complete queue.BlockBackgroundWorkCompleting.Set(); await Task.Run(() => queue.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3))); Assert.False(queue.HasPendingNotifications, "Queue should have processed all notifications"); Assert.False(queue.IsScheduledOrRunning, "Queue should not have restarted"); }
public async Task WorkspaceChanged_DocumentChanged_PartialComponent_UpdatesProjectState_AfterDelay() { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator) { EnqueueDelay = 1, BlockDelayedUpdateWorkEnqueue = new ManualResetEventSlim(initialState: false), }; Workspace.TryApplyChanges(SolutionWithTwoProjects); var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace); projectManager.ProjectAdded(HostProjectOne); workspaceStateGenerator.ClearQueue(); var sourceText = SourceText.From( $@" public partial class TestComponent : {ComponentsApi.IComponent.MetadataName} {{}} namespace Microsoft.AspNetCore.Components {{ public interface IComponent {{}} }} "); var syntaxTreeRoot = CSharpSyntaxTree.ParseText(sourceText).GetRoot(); var solution = SolutionWithTwoProjects .WithDocumentText(PartialComponentClassDocumentId, sourceText) .WithDocumentSyntaxRoot(PartialComponentClassDocumentId, syntaxTreeRoot, PreservationMode.PreserveIdentity); var document = solution.GetDocument(PartialComponentClassDocumentId); // The change detector only operates when a semantic model / syntax tree is available. await document.GetSyntaxRootAsync(); await document.GetSemanticModelAsync(); var e = new WorkspaceChangeEventArgs(WorkspaceChangeKind.DocumentChanged, oldSolution: solution, newSolution: solution, projectId: ProjectNumberOne.Id, PartialComponentClassDocumentId); // Act detector.Workspace_WorkspaceChanged(Workspace, e); // Assert // // The change hasn't come through yet. Assert.Empty(workspaceStateGenerator.UpdateQueue); detector.BlockDelayedUpdateWorkEnqueue.Set(); await detector._deferredUpdates.Single().Value; var update = Assert.Single(workspaceStateGenerator.UpdateQueue); Assert.Equal(update.workspaceProject.Id, ProjectNumberOne.Id); Assert.Equal(update.projectSnapshot.FilePath, HostProjectOne.FilePath); }
public async Task WorkspaceChanged_DocumentChanged_PartialComponent_UpdatesProjectState_AfterDelay() { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher, WorkQueue); WorkQueueTestAccessor.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false); Workspace.TryApplyChanges(SolutionWithTwoProjects); var projectManager = new TestProjectSnapshotManager(Dispatcher, new[] { detector }, Workspace); await Dispatcher.RunOnDispatcherThreadAsync(() => projectManager.ProjectAdded(HostProjectOne), CancellationToken.None).ConfigureAwait(false); workspaceStateGenerator.ClearQueue(); var sourceText = SourceText.From( $@" public partial class TestComponent : {ComponentsApi.IComponent.MetadataName} {{}} namespace Microsoft.AspNetCore.Components {{ public interface IComponent {{}} }} "); var syntaxTreeRoot = await CSharpSyntaxTree.ParseText(sourceText).GetRootAsync(); var solution = SolutionWithTwoProjects .WithDocumentText(PartialComponentClassDocumentId, sourceText) .WithDocumentSyntaxRoot(PartialComponentClassDocumentId, syntaxTreeRoot, PreservationMode.PreserveIdentity); var document = solution.GetDocument(PartialComponentClassDocumentId); // The change detector only operates when a semantic model / syntax tree is available. await document.GetSyntaxRootAsync(); await document.GetSemanticModelAsync(); var e = new WorkspaceChangeEventArgs(WorkspaceChangeKind.DocumentChanged, oldSolution: solution, newSolution: solution, projectId: ProjectNumberOne.Id, PartialComponentClassDocumentId); // Act detector.Workspace_WorkspaceChanged(Workspace, e); // Assert // // The change hasn't come through yet. Assert.Empty(workspaceStateGenerator.UpdateQueue); WorkQueueTestAccessor.BlockBackgroundWorkStart.Set(); WorkQueueTestAccessor.NotifyBackgroundWorkCompleted.Wait(); var update = Assert.Single(workspaceStateGenerator.UpdateQueue); Assert.Equal(update.WorkspaceProject.Id, ProjectNumberOne.Id); Assert.Equal(update.ProjectSnapshot.FilePath, HostProjectOne.FilePath); }
public void WorkspaceChanged_ProjectRemovedEvent_QueuesProjectStateRemoval() { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator); var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace); projectManager.ProjectAdded(HostProjectOne); projectManager.ProjectAdded(HostProjectTwo); var solution = SolutionWithTwoProjects.RemoveProject(ProjectNumberOne.Id); var e = new WorkspaceChangeEventArgs(WorkspaceChangeKind.ProjectRemoved, oldSolution: SolutionWithTwoProjects, newSolution: solution, projectId: ProjectNumberOne.Id); // Act detector.Workspace_WorkspaceChanged(Workspace, e); // Assert Assert.Collection( workspaceStateGenerator.UpdateQueue, p => Assert.Null(p.workspaceProject)); }
public void WorkspaceChanged_SolutionEvents_EnqueuesUpdatesForProjectsInSolution(WorkspaceChangeKind kind) { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator); var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace); projectManager.ProjectAdded(HostProjectOne); projectManager.ProjectAdded(HostProjectTwo); var e = new WorkspaceChangeEventArgs(kind, oldSolution: EmptySolution, newSolution: SolutionWithTwoProjects); // Act detector.Workspace_WorkspaceChanged(Workspace, e); // Assert Assert.Collection( workspaceStateGenerator.UpdateQueue, p => Assert.Equal(ProjectNumberOne.Id, p.workspaceProject.Id), p => Assert.Equal(ProjectNumberTwo.Id, p.workspaceProject.Id)); }
public async Task Queue_ProcessesNotifications_AndGoesBackToSleep() { // Arrange var projectManager = new TestProjectSnapshotManager(Dispatcher, Workspace); projectManager.ProjectAdded(HostProject1); projectManager.ProjectAdded(HostProject2); projectManager.DocumentAdded(HostProject1, Documents[0], null); projectManager.DocumentAdded(HostProject1, Documents[1], null); var project = projectManager.GetLoadedProject(HostProject1.FilePath); var queue = new BackgroundDocumentGenerator(Dispatcher, DynamicFileInfoProvider) { Delay = TimeSpan.FromMilliseconds(1), BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false), NotifyBackgroundWorkStarting = new ManualResetEventSlim(initialState: false), BlockBackgroundWorkCompleting = new ManualResetEventSlim(initialState: false), NotifyBackgroundWorkCompleted = new ManualResetEventSlim(initialState: false), }; queue.Initialize(projectManager); // Act & Assert queue.Enqueue(project, project.GetDocument(Documents[0].FilePath)); Assert.True(queue.IsScheduledOrRunning, "Queue should be scheduled during Enqueue"); Assert.True(queue.HasPendingNotifications, "Queue should have a notification created during Enqueue"); // Allow the background work to proceed. queue.BlockBackgroundWorkStart.Set(); queue.BlockBackgroundWorkCompleting.Set(); await Task.Run(() => queue.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3))); Assert.False(queue.IsScheduledOrRunning, "Queue should not have restarted"); Assert.False(queue.HasPendingNotifications, "Queue should have processed all notifications"); }
public async Task ProcessDocument_LongDocumentParse_DoesNotUpdateAfterSuppress() { // Arrange var projectManager = new TestProjectSnapshotManager(Dispatcher, Workspace); projectManager.ProjectAdded(HostProject1); // We utilize a task completion source here so we can "fake" a document parse taking a significant amount of time var tcs = new TaskCompletionSource <TextAndVersion>(); var textLoader = new Mock <TextLoader>(MockBehavior.Strict); textLoader.Setup(loader => loader.LoadTextAndVersionAsync(It.IsAny <Workspace>(), It.IsAny <DocumentId>(), It.IsAny <CancellationToken>())) .Returns(tcs.Task); var hostDocument = Documents[0]; var project = projectManager.GetLoadedProject(HostProject1.FilePath); var queue = new BackgroundDocumentGenerator(Dispatcher, DynamicFileInfoProvider) { Delay = TimeSpan.FromMilliseconds(1), NotifyBackgroundWorkCompleted = new ManualResetEventSlim(initialState: false), NotifyBackgroundCapturedWorkload = new ManualResetEventSlim(initialState: false), }; queue.Initialize(projectManager); // We trigger enqueued notifications via adding/opening to the project manager projectManager.AllowNotifyListeners = true; // Act & Assert projectManager.DocumentAdded(HostProject1, hostDocument, textLoader.Object); queue.NotifyBackgroundCapturedWorkload.Wait(); projectManager.DocumentOpened(HostProject1.FilePath, hostDocument.FilePath, SourceText.From(string.Empty)); // Verify document was suppressed because it was opened Assert.Null(DynamicFileInfoProvider.DynamicDocuments[hostDocument.FilePath]); // Unblock document processing tcs.SetResult(TextAndVersion.Create(SourceText.From(string.Empty), VersionStamp.Default)); await Task.Run(() => queue.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3))); // Validate that even though document parsing took a significant amount of time that the dynamic document wasn't "unsuppressed" Assert.Null(DynamicFileInfoProvider.DynamicDocuments[hostDocument.FilePath]); }
public void WorkspaceChanged_ProjectAddedEvent_AddsProject() { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator); var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace); projectManager.ProjectAdded(HostProjectThree); var solution = SolutionWithOneProject; var e = new WorkspaceChangeEventArgs(WorkspaceChangeKind.ProjectAdded, oldSolution: EmptySolution, newSolution: solution, projectId: ProjectNumberThree.Id); // Act detector.Workspace_WorkspaceChanged(Workspace, e); // Assert Assert.Collection( workspaceStateGenerator.UpdateQueue, p => Assert.Equal(ProjectNumberThree.Id, p.workspaceProject.Id)); }
public async Task WorkspaceChanged_DocumentChanged_BackgroundVirtualCS_UpdatesProjectState_AfterDelay() { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator) { EnqueueDelay = 1, BlockDelayedUpdateWorkEnqueue = new ManualResetEventSlim(initialState: false), }; Workspace.TryApplyChanges(SolutionWithTwoProjects); var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace); projectManager.ProjectAdded(HostProjectOne); workspaceStateGenerator.ClearQueue(); var solution = SolutionWithTwoProjects.WithDocumentText(BackgroundVirtualCSharpDocumentId, SourceText.From("public class Foo{}")); var e = new WorkspaceChangeEventArgs(WorkspaceChangeKind.DocumentChanged, oldSolution: SolutionWithTwoProjects, newSolution: solution, projectId: ProjectNumberOne.Id, BackgroundVirtualCSharpDocumentId); // Act detector.Workspace_WorkspaceChanged(Workspace, e); // Assert // // The change hasn't come through yet. Assert.Empty(workspaceStateGenerator.UpdateQueue); detector.BlockDelayedUpdateWorkEnqueue.Set(); await detector._deferredUpdates.Single().Value; var update = Assert.Single(workspaceStateGenerator.UpdateQueue); Assert.Equal(update.workspaceProject.Id, ProjectNumberOne.Id); Assert.Equal(update.projectSnapshot.FilePath, HostProjectOne.FilePath); }
public async Task WorkspaceChanged_ProjectAddedEvent_AddsProject() { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher, WorkQueue) { NotifyWorkspaceChangedEventComplete = new ManualResetEventSlim(initialState: false), }; var projectManager = new TestProjectSnapshotManager(Dispatcher, new[] { detector }, Workspace); await Dispatcher.RunOnDispatcherThreadAsync(() => projectManager.ProjectAdded(HostProjectThree), CancellationToken.None).ConfigureAwait(false); var solution = SolutionWithOneProject; var e = new WorkspaceChangeEventArgs(WorkspaceChangeKind.ProjectAdded, oldSolution: EmptySolution, newSolution: solution, projectId: ProjectNumberThree.Id); // Act detector.Workspace_WorkspaceChanged(Workspace, e); detector.NotifyWorkspaceChangedEventComplete.Wait(); WorkQueueTestAccessor.NotifyBackgroundWorkCompleted.Wait(); // Assert Assert.Collection( workspaceStateGenerator.UpdateQueue, p => Assert.Equal(ProjectNumberThree.Id, p.WorkspaceProject.Id)); }
public async Task Queue_ProcessesNotifications_AndRestarts() { // Arrange var projectManager = new TestProjectSnapshotManager(Dispatcher, Workspace); projectManager.ProjectAdded(HostProject1); projectManager.ProjectAdded(HostProject2); projectManager.DocumentAdded(HostProject1, Documents[0], null); projectManager.DocumentAdded(HostProject1, Documents[1], null); var project = projectManager.GetLoadedProject(HostProject1.FilePath); var queue = new BackgroundDocumentGenerator(Dispatcher, DynamicFileInfoProvider, DivergenceChecker) { Delay = TimeSpan.FromMilliseconds(1), BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false), NotifyBackgroundWorkStarting = new ManualResetEventSlim(initialState: false), NotifyBackgroundCapturedWorkload = new ManualResetEventSlim(initialState: false), BlockBackgroundWorkCompleting = new ManualResetEventSlim(initialState: false), NotifyBackgroundWorkCompleted = new ManualResetEventSlim(initialState: false), }; queue.Initialize(projectManager); // Act & Assert queue.Enqueue(project, project.GetDocument(Documents[0].FilePath)); Assert.True(queue.IsScheduledOrRunning, "Queue should be scheduled during Enqueue"); Assert.True(queue.HasPendingNotifications, "Queue should have a notification created during Enqueue"); // Allow the background work to start. queue.BlockBackgroundWorkStart.Set(); await Task.Run(() => queue.NotifyBackgroundWorkStarting.Wait(TimeSpan.FromSeconds(1))); Assert.True(queue.IsScheduledOrRunning, "Worker should be processing now"); await Task.Run(() => queue.NotifyBackgroundCapturedWorkload.Wait(TimeSpan.FromSeconds(1))); Assert.False(queue.HasPendingNotifications, "Worker should have taken all notifications"); queue.Enqueue(project, project.GetDocument(Documents[1].FilePath)); Assert.True(queue.HasPendingNotifications); // Now we should see the worker restart when it finishes. // Allow work to complete, which should restart the timer. queue.BlockBackgroundWorkCompleting.Set(); await Task.Run(() => queue.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3))); queue.NotifyBackgroundWorkCompleted.Reset(); // It should start running again right away. Assert.True(queue.IsScheduledOrRunning, "Queue should be scheduled during Enqueue"); Assert.True(queue.HasPendingNotifications, "Queue should have a notification created during Enqueue"); // Allow the background work to proceed. queue.BlockBackgroundWorkStart.Set(); queue.BlockBackgroundWorkCompleting.Set(); await Task.Run(() => queue.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3))); Assert.False(queue.IsScheduledOrRunning, "Queue should not have restarted"); Assert.False(queue.HasPendingNotifications, "Queue should have processed all notifications"); }
public async Task DocumentChanged_ReparsesRelatedFiles() { // Arrange var projectManager = new TestProjectSnapshotManager(Dispatcher, Workspace) { AllowNotifyListeners = true, }; var documents = new[] { TestProjectData.SomeProjectComponentFile1, TestProjectData.SomeProjectImportFile }; projectManager.ProjectAdded(HostProject1); for (var i = 0; i < documents.Length; i++) { projectManager.DocumentAdded(HostProject1, documents[i], null); } var queue = new BackgroundDocumentGenerator(Dispatcher, DynamicFileInfoProvider) { Delay = TimeSpan.FromMilliseconds(1), BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false), NotifyBackgroundWorkStarting = new ManualResetEventSlim(initialState: false), NotifyBackgroundCapturedWorkload = new ManualResetEventSlim(initialState: false), BlockBackgroundWorkCompleting = new ManualResetEventSlim(initialState: false), NotifyBackgroundWorkCompleted = new ManualResetEventSlim(initialState: false), }; var changedSourceText = SourceText.From("@inject DateTime Time"); queue.Initialize(projectManager); // Act & Assert projectManager.DocumentChanged(HostProject1.FilePath, TestProjectData.SomeProjectImportFile.FilePath, changedSourceText); Assert.True(queue.IsScheduledOrRunning, "Queue should be scheduled during Enqueue"); Assert.True(queue.HasPendingNotifications, "Queue should have a notification created during Enqueue"); for (var i = 0; i < documents.Length; i++) { var key = new DocumentKey(HostProject1.FilePath, documents[i].FilePath); Assert.True(queue.Work.ContainsKey(key)); } // Allow the background work to start. queue.BlockBackgroundWorkStart.Set(); await Task.Run(() => queue.NotifyBackgroundWorkStarting.Wait(TimeSpan.FromSeconds(1))); Assert.True(queue.IsScheduledOrRunning, "Worker should be processing now"); await Task.Run(() => queue.NotifyBackgroundCapturedWorkload.Wait(TimeSpan.FromSeconds(1))); Assert.False(queue.HasPendingNotifications, "Worker should have taken all notifications"); // Allow work to complete queue.BlockBackgroundWorkCompleting.Set(); await Task.Run(() => queue.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3))); Assert.False(queue.HasPendingNotifications, "Queue should have processed all notifications"); Assert.False(queue.IsScheduledOrRunning, "Queue should not have restarted"); }