Skip to content
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

Add service which exists to tell OOP about solution events #64127

Conversation

CyrusNajmabadi
Copy link
Member

Note: this is going into a feature branch, as i expect several more PRs necessary here.

The general premise here is that we are moving away from SolutionCrawler and want to have no 1st class roslyn features using it. One snag in this is that Unit-Testing still uses solution-crawler and needs more time than we would prefer to fully move off of it.

To support their longer migration path, while also getting us off of Solution-Crawler, we intend to transfer ownership fo Solution-Crawler to the unit testing team for them to maintain for their single use case, until they've moved onto a new approach for doing test-discovery.

The SolutionCrawler code (ne UnitTestingSolutionCrawler) will live in the Unit-Testing EA layer and will be launched/maintained by them. We can def assist with it at times. But the intent is for this to be entirely legacy, with only tiny changes put into it while UnitTesting moves to a modern solution.

To assist this though, the UNitTestingSolutionCrawler does need to know what's going on in the Workspace itself. As we intend to not have a Workspace in OOP, and we def won't have a RemoteWorkspace issuing WorkspaceEvents in OOP, we need a solution that will allow the new UnitTestingSolutionCrawler to know what's going on so it can decide what crawling steps to take.

To taht end, this PR adds a new service+oop combo that exists purely to hear about host Workspace-Events and remote them to OOP for OOP clients to respond to. This combo is lightweight and doesn't do anything but just send the events over. On the OOP side then, UnitTesting will have a listener for this that then forwards the events to the UnitTestingSolutionCrawler.

This still means we have some code for this scenarios owned and operated by roslyn. HOwever:

  1. This event-remoting code is extremely trivial and required no complex logic or state management.
  2. All complex logic and state management around crawling will be contained entirely in the UnitTesting EA lib and will be owned by them.
  3. THis will let us get off of having a RemoteWorkspace entirely. All OOP calls will simply be functional service calls that run off of Solution snapshots.
  4. This new code can also go away once UnitTesting moves to a new system. For example, one where they "pull" on their test discoverer, or maybe one where they use Source-GEnerators to emit the discovered test information.

namespace Microsoft.CodeAnalysis.SolutionEvents
{
[ExportEventListener(WellKnownEventListeners.Workspace, WorkspaceKind.Host), Shared]
internal sealed partial class HostSolutionEventsWorkspaceEventListener : IEventListener<object>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the part that runs in VS and connects to the actual VS workspace and hears about changes to it. It is very similar in that regard to the equivalent HostSolutionCrawlerWorkspaceEventListener type.

SolutionEvent ev,
CancellationToken cancellationToken)
{
if (ev.DocumentOpenArgs != null)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this method/switch corresponds to equivalent code in WorkCoordinator which suscribes to and listens for these events off of hte workspace. Once we move WorkCoordinator to EA layer for unit testing, it will just listen for tehse new events.

ValueTask OnSolutionChangedAsync(Checksum oldSolutionChecksum, Checksum newSolutionChecksum, CancellationToken cancellationToken);
ValueTask OnProjectChangedAsync(Checksum oldSolutionChecksum, Checksum newSolutionChecksum, ProjectId projectId, CancellationToken cancellationToken);
ValueTask OnDocumentChangedAsync(Checksum oldSolutionChecksum, Checksum newSolutionChecksum, DocumentId documentId, CancellationToken cancellationToken);
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this defines the api on the remote side which hears about the workspace events and will dispatch them to different listeners.

}

[ExportWorkspaceService(typeof(ISolutionEventsAggregationService)), Shared]
internal class DefaultSolutionEventsAggregationService : ISolutionEventsAggregationService
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aggregation service that pulls in the individual listener services and dispatches to all of them.


namespace Microsoft.CodeAnalysis.Remote
{
internal sealed class RemoteSolutionEventsAggregationService : BrokeredServiceBase, IRemoteSolutionEventsAggregationService
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RemoteSolutionEventsAggregationService

Nit: Consider renaming the containing dir to SolutionEventsAggregation to match the service name (w/o Remote- prefix and -Service suffix).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gotcha.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally think this is fine as teh general component is the 'solution events' component. This is just the remote side of one particular interface of that component. keeping the component name (i.e. the folder) consistent across all the projects this touches is desirable to me (and matches what we do with our other components).

@@ -24,6 +24,7 @@
using Microsoft.CodeAnalysis.NavigationBar;
using Microsoft.CodeAnalysis.Rename;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.SolutionEvents;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SolutionEvents

Do we need a new namespace? Workspace event related types are in Microsoft.CodeAnalysis

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like a new namespace here to keep this isolated.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok


namespace Microsoft.CodeAnalysis.SolutionCrawler
{
[DataContract]
internal partial struct InvocationReasons : IEnumerable<string>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InvocationReasons

Can this simply be a flags enum?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the goal here is not change anything, but to use the existing concepts that solution-crawler is already doing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In-proc we seem to have pre-allocated instances of this, but OOP deserialization will allocate a new one each call.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok. will move to enum in followup :)


namespace Microsoft.CodeAnalysis.SolutionEvents
{
internal interface ISolutionEventsAggregationService : IWorkspaceService
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ISolutionEventsAggregationService

ILegacySolutionEventAggregator?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, i can add Legacy to the name.


namespace Microsoft.CodeAnalysis.SolutionCrawler
{
[DataContract]
internal partial struct InvocationReasons : IEnumerable<string>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move out of SolutionCrawler namespace to avoid dependency of the new interfaces on SolutionCrawler

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the next PR does that.

@CyrusNajmabadi
Copy link
Member Author

@tmat i can roll the feedback into the next PR. note that this is all going into a feature branch currently.

@CyrusNajmabadi CyrusNajmabadi merged commit e5d1e48 into dotnet:features/solutionEvents Sep 20, 2022
@CyrusNajmabadi CyrusNajmabadi deleted the features/solutionEvents branch September 20, 2022 04:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants