From e5695dd9763532229b3cfc7d6488a136baa37d9c Mon Sep 17 00:00:00 2001 From: lilla28 Date: Fri, 31 Mar 2023 18:07:03 +0200 Subject: [PATCH] Some refactoring, base end to end tests --- .../dotnet/ProcessExplorer.sln | 7 + .../IProcessInfoAggregator.cs | 17 +- .../Protos/ProcessExplorerMessages.proto | 11 +- .../ProcessExplorer.Abstractions.csproj | 17 ++ .../Processes/ProcessInfoData.cs | 36 +--- .../Processes/ProcessInfoManager.cs | 78 ++++---- .../Subsystems/SubsystemInfo.cs | 1 + .../Factories/ProcessAggregatorFactory.cs | 6 - .../Infrastructure/Communicator.cs | 2 +- .../ProcessInfoAggregator.cs | 63 ++++-- .../Processes/ProcessInformation.cs | 15 +- .../Subsystems/SubsystemController.cs | 1 + .../SourceGeneratedLoggerExtensions.cs | 3 + .../ProcessExplorer.Server.csproj | 10 - .../Abstractions/ProcessExplorerServer.cs | 4 +- .../Server/GrpcServer/GrpcListenerService.cs | 23 ++- .../Server/Helper/ProtoConvertHelper.cs | 8 +- .../Infrastructure/Grpc/GrpcUIHandler.cs | 56 ++++-- .../ProcessExplorerMessageHandlerService.cs | 7 +- .../Server/MessageHandler.cs | 2 +- .../ProcessInfoAggregator.Tests.cs | 17 +- .../EndToEndTests.cs | 180 ++++++++++++++++++ ...essExplorer.Server.IntegrationTests.csproj | 32 ++++ 23 files changed, 418 insertions(+), 178 deletions(-) rename Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/{ProcessExplorer.Server/Server/Infrastructure/Grpc => ProcessExplorer.Abstractions/Infrastructure}/Protos/ProcessExplorerMessages.proto (94%) create mode 100644 Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/test/ProcessExplorer.Server.EndToEndTests/EndToEndTests.cs create mode 100644 Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/test/ProcessExplorer.Server.EndToEndTests/ProcessExplorer.Server.IntegrationTests.csproj diff --git a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/ProcessExplorer.sln b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/ProcessExplorer.sln index ce5ab0432..4620060d7 100644 --- a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/ProcessExplorer.sln +++ b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/ProcessExplorer.sln @@ -19,6 +19,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProcessExplorer.Abstraction EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProcessExplorer.Core.Tests", "test\ProcessExplorer.Core.Tests\ProcessExplorer.Core.Tests.csproj", "{3C2B4F9E-CA84-4FB1-AE2B-CC61886A3CE7}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProcessExplorer.Server.IntegrationTests", "test\ProcessExplorer.Server.EndToEndTests\ProcessExplorer.Server.IntegrationTests.csproj", "{18B9042E-0D77-4917-97FF-14BC34085385}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -45,6 +47,10 @@ Global {3C2B4F9E-CA84-4FB1-AE2B-CC61886A3CE7}.Debug|Any CPU.Build.0 = Debug|Any CPU {3C2B4F9E-CA84-4FB1-AE2B-CC61886A3CE7}.Release|Any CPU.ActiveCfg = Release|Any CPU {3C2B4F9E-CA84-4FB1-AE2B-CC61886A3CE7}.Release|Any CPU.Build.0 = Release|Any CPU + {18B9042E-0D77-4917-97FF-14BC34085385}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {18B9042E-0D77-4917-97FF-14BC34085385}.Debug|Any CPU.Build.0 = Debug|Any CPU + {18B9042E-0D77-4917-97FF-14BC34085385}.Release|Any CPU.ActiveCfg = Release|Any CPU + {18B9042E-0D77-4917-97FF-14BC34085385}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -55,6 +61,7 @@ Global {AF40EAD5-8A98-465E-BF26-2EB06274A384} = {3413C687-1DD1-4751-8C4F-0CD308248CB2} {51110571-1082-4790-AA00-3DDDEE80641A} = {3413C687-1DD1-4751-8C4F-0CD308248CB2} {3C2B4F9E-CA84-4FB1-AE2B-CC61886A3CE7} = {55657FBD-CD23-40A2-B8E9-2BBE734924CC} + {18B9042E-0D77-4917-97FF-14BC34085385} = {55657FBD-CD23-40A2-B8E9-2BBE734924CC} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {819F883C-DDD0-4F2B-82C5-820D4D6AB446} diff --git a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Abstractions/IProcessInfoAggregator.cs b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Abstractions/IProcessInfoAggregator.cs index bb1f3c443..d48862436 100644 --- a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Abstractions/IProcessInfoAggregator.cs +++ b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Abstractions/IProcessInfoAggregator.cs @@ -21,6 +21,11 @@ namespace ProcessExplorer.Abstractions; public interface IProcessInfoAggregator : IDisposable { + /// + /// Main process id to watch. + /// + public int MainProcessId { get; } + /// /// Adds a runtime information to the collection. /// @@ -37,8 +42,8 @@ public interface IProcessInfoAggregator : IDisposable /// /// Sets Compose PID. /// - /// - void SetComposePid(int pid); + /// + void SetMainProcessId(int processId); /// /// Sets the SubsystemController. @@ -115,8 +120,8 @@ public interface IProcessInfoAggregator : IDisposable /// /// Sets the processes, which is gotten from the ModuleLoader. /// - /// - void InitProcesses(ReadOnlySpan pids); + /// + void InitProcesses(ReadOnlySpan processIds); /// /// Initializes the subsystems taken from the user defined manifest. @@ -165,9 +170,9 @@ public interface IProcessInfoAggregator : IDisposable /// /// Adds processes to watch to the existing watchable process ids list. /// - /// + /// /// - ValueTask AddProcesses(ReadOnlySpan processes); + ValueTask AddProcesses(ReadOnlySpan processIds); /// /// Puts the given subsystem into the queue to send subsystem state changed information to the UI's. diff --git a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Server/Infrastructure/Grpc/Protos/ProcessExplorerMessages.proto b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Abstractions/Infrastructure/Protos/ProcessExplorerMessages.proto similarity index 94% rename from Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Server/Infrastructure/Grpc/Protos/ProcessExplorerMessages.proto rename to Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Abstractions/Infrastructure/Protos/ProcessExplorerMessages.proto index 2a9916003..fe6b2e697 100644 --- a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Server/Infrastructure/Grpc/Protos/ProcessExplorerMessages.proto +++ b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Abstractions/Infrastructure/Protos/ProcessExplorerMessages.proto @@ -1,6 +1,6 @@ syntax = "proto3"; -option csharp_namespace = "ProcessExplorer.Server.Server.Infrastructure.Protos"; +option csharp_namespace = "ProcessExplorer.Abstractions.Infrastructure.Protos"; import "google/protobuf/duration.proto"; import "google/protobuf/empty.proto"; @@ -12,7 +12,9 @@ service ProcessExplorerMessageHandler{ } message Message{ - ActionType action = 1; + oneof action1 { + ActionType action = 1; + }; optional string assemblyId = 2; repeated Process processes = 3; repeated Registration registrations = 4; @@ -25,6 +27,7 @@ message Message{ map multipleRuntimeInfo = 11; int32 periodOfDelay = 12; map processStatusChanges = 13; + optional string description = 14; } enum ActionType{ @@ -50,12 +53,10 @@ enum ActionType{ TerminateSubsystemsAction = 19; LaunchSubsystemsAction = 20; LaunchSubsystemsWithDelayAction = 21; + SubscriptionAliveAction = 22; } message Process{ - optional string instanceId = 1; - optional string uiType = 2; - optional string uiHint = 3; optional string startTime = 4; optional google.protobuf.Duration processorUsageTime = 5; optional int64 physicalMemoryUsageBit = 6; diff --git a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Abstractions/ProcessExplorer.Abstractions.csproj b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Abstractions/ProcessExplorer.Abstractions.csproj index a8155d221..5aefe333c 100644 --- a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Abstractions/ProcessExplorer.Abstractions.csproj +++ b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Abstractions/ProcessExplorer.Abstractions.csproj @@ -7,9 +7,20 @@ + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + @@ -19,4 +30,10 @@ + + + Both + + + diff --git a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Abstractions/Processes/ProcessInfoData.cs b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Abstractions/Processes/ProcessInfoData.cs index c291c104a..9124f3f17 100644 --- a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Abstractions/Processes/ProcessInfoData.cs +++ b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Abstractions/Processes/ProcessInfoData.cs @@ -15,45 +15,13 @@ namespace ProcessExplorer.Abstractions.Processes; -public struct ProcessInfoData +public class ProcessInfoData { - public ProcessInfoData( - string? startTime, - TimeSpan? processorUsageTime, - long? physicalMemoryUsageBit, - string? processName, - int pID, - int? priorityLevel, - string? processPriorityClass, - IEnumerable threads, - long? virtualMemorySize, - int? parentId, - long? privateMemoryUsage, - string? processStatus, - float? memoryUsage, - float? processorUsage) - { - StartTime = startTime; - ProcessorUsageTime = processorUsageTime; - PhysicalMemoryUsageBit = physicalMemoryUsageBit; - ProcessName = processName; - PID = pID; - PriorityLevel = priorityLevel; - ProcessPriorityClass = processPriorityClass; - Threads = threads; - VirtualMemorySize = virtualMemorySize; - ParentId = parentId; - PrivateMemoryUsage = privateMemoryUsage; - ProcessStatus = processStatus; - MemoryUsage = memoryUsage; - ProcessorUsage = processorUsage; - } - public string? StartTime { get; set; } public TimeSpan? ProcessorUsageTime { get; set; } public long? PhysicalMemoryUsageBit { get; set; } public string? ProcessName { get; set; } - public int PID { get; set; } + public int ProcessId { get; set; } public int? PriorityLevel { get; set; } public string? ProcessPriorityClass { get; set; } public IEnumerable Threads { get; set; } = Enumerable.Empty(); diff --git a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Abstractions/Processes/ProcessInfoManager.cs b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Abstractions/Processes/ProcessInfoManager.cs index 975d9d039..899729e8d 100644 --- a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Abstractions/Processes/ProcessInfoManager.cs +++ b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Abstractions/Processes/ProcessInfoManager.cs @@ -20,7 +20,7 @@ namespace ProcessExplorer.Abstractions.Processes; -public abstract class ProcessInfoManager : IDisposable +public abstract class ProcessInfoManager : IDisposable //Create an interface { private ProcessCreatedHandler? _processCreatedHandler; private ProcessModifiedHandler? _processModifiedHandler; @@ -78,42 +78,42 @@ public void SetHandlers( _processesModifiedHandler = processesModifiedHandler; } - public void SetComposePid(int pid) + public void SetComposePid(int processId) { - _composePid = pid; + _composePid = processId; } - public bool ContainsId(int pid) + public bool ContainsId(int processId) { lock (_locker) { - return _processIds.Contains(pid); + return _processIds.Contains(processId); } } - public void AddProcess(int pid) + public void AddProcess(int processId) { lock (_locker) { - if (pid == 0) return; + if (processId == 0) return; - _processIds.Add(pid); + _processIds.Add(processId); } } - public void RemoveProcessId(int pid) + public void RemoveProcessId(int processId) { lock (_locker) { - _processIds.Remove(pid); + _processIds.Remove(processId); } } - public void SetProcessIds(ReadOnlySpan ids) + public void SetProcessIds(ReadOnlySpan processIds) { lock (_locker) { - foreach (var id in ids) + foreach (var id in processIds) { if (_processIds.Contains(id)) continue; _processIds.Add(id); @@ -150,16 +150,14 @@ public void ClearProcessIds() /// /// Returns the memory usage (%) of the given process. /// - /// /// - public abstract float GetMemoryUsage(int id, string processName); + public abstract float GetMemoryUsage(int processId, string processName); /// /// Returns the CPU usage (%) of the given process. /// - /// /// - public abstract float GetCpuUsage(int id, string processName); + public abstract float GetCpuUsage(int processId, string processName); /// /// Continuously watching created processes. @@ -183,13 +181,13 @@ private bool IsComposeProcess(int processId) if (processId == _composePid || ContainsId(processId)) return true; - var ppid = GetParentId(processId, Process.GetProcessById(processId).ProcessName); + var parentProcessId = GetParentId(processId, Process.GetProcessById(processId).ProcessName); - if (ppid == null || ppid == 0) return false; + if (parentProcessId == null || parentProcessId == 0) return false; - if (ContainsId((int)ppid)) return true; + if (ContainsId((int)parentProcessId)) return true; - return IsComposeProcess(Convert.ToInt32(ppid)); + return IsComposeProcess(Convert.ToInt32(parentProcessId)); } /// @@ -197,38 +195,38 @@ private bool IsComposeProcess(int processId) /// /// /// - public abstract ReadOnlySpan AddChildProcesses(int pid, string? processName); + public abstract ReadOnlySpan AddChildProcesses(int processId, string? processName); /// /// Checks if a process belongs to the Compose. /// - /// - public bool CheckIfIsComposeProcess(int pid) + /// + public bool CheckIfIsComposeProcess(int processId) { - return IsComposeProcess(pid); + return IsComposeProcess(processId); } - public void SendNewProcessUpdate(int pid) + public void SendNewProcessUpdate(int processId) { - _processCreatedHandler?.Invoke(pid); + _processCreatedHandler?.Invoke(processId); } /// /// Sends a terminated process information to publish /// - /// - public void SendTerminatedProcessUpdate(int pid) + /// + public void SendTerminatedProcessUpdate(int processId) { - ProcessTerminated(pid); + ProcessTerminated(processId); } /// /// Sends a modified process information to publish /// - /// - public void SendProcessModifiedUpdate(int pid) + /// + public void SendProcessModifiedUpdate(int processId) { - _processModifiedHandler?.Invoke(pid); + _processModifiedHandler?.Invoke(processId); } public void SetDeadProcessRemovalDelay(int delay) @@ -255,31 +253,31 @@ private void ProcessTerminated(int pid) if (!TryDeleteProcess(pid)) _logger.CannotTerminateProcessError(pid); } - private bool TryDeleteProcess(int pid) + private bool TryDeleteProcess(int processId) { try { - _logger.ProcessTerminatedInformation(pid); - _processStatusChangedHandler?.Invoke(new(pid, Status.Terminated)); - RemoveProcessAfterTimeout(pid); + _logger.ProcessTerminatedInformation(processId); + _processStatusChangedHandler?.Invoke(new(processId, Status.Terminated)); + RemoveProcessAfterTimeout(processId); return true; } catch (Exception exception) { - _logger.PpidExpected(pid, exception); + _logger.PpidExpected(processId, exception); } return false; } - private void RemoveProcessAfterTimeout(int item) + private async void RemoveProcessAfterTimeout(int processId) { - Task.Run(() => + await Task.Run(() => { Task.Delay(_delayTime); var ids = GetProcessIds(); _processesModifiedHandler?.Invoke(ids); - _processTerminatedHandler?.Invoke(item); + _processTerminatedHandler?.Invoke(processId); }); } } diff --git a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Abstractions/Subsystems/SubsystemInfo.cs b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Abstractions/Subsystems/SubsystemInfo.cs index 8919a0255..9348b4f11 100644 --- a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Abstractions/Subsystems/SubsystemInfo.cs +++ b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Abstractions/Subsystems/SubsystemInfo.cs @@ -12,6 +12,7 @@ namespace ProcessExplorer.Abstractions.Subsystems; +//TODO(Lilla): define ProtoContract to derive it implicitly without protoconverthelper public class SubsystemInfo { public string Name { get; set; } = string.Empty; diff --git a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Core/Factories/ProcessAggregatorFactory.cs b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Core/Factories/ProcessAggregatorFactory.cs index 32316237e..0bf4df188 100644 --- a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Core/Factories/ProcessAggregatorFactory.cs +++ b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Core/Factories/ProcessAggregatorFactory.cs @@ -10,7 +10,6 @@ // or implied. See the License for the specific language governing permissions // and limitations under the License. -using LocalCollector.Communicator; using Microsoft.Extensions.Logging; using ProcessExplorer.Abstractions; using ProcessExplorer.Abstractions.Processes; @@ -20,11 +19,6 @@ namespace ProcessExplorer.Core.Factories; public static class ProcessAggregatorFactory { - public static ICommunicator CreateCommunicator(IProcessInfoAggregator processAggregator) - { - return new Infrastructure.Communicator(processAggregator); - } - public static IProcessInfoAggregator CreateProcessInfoAggregator(ILogger logger, ProcessInfoManager processInfoManager, ISubsystemController? subsystemController = null) { return new ProcessInfoAggregator(logger, processInfoManager, subsystemController); diff --git a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Core/Infrastructure/Communicator.cs b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Core/Infrastructure/Communicator.cs index f1b55285d..5bf282da2 100644 --- a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Core/Infrastructure/Communicator.cs +++ b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Core/Infrastructure/Communicator.cs @@ -19,7 +19,7 @@ namespace ProcessExplorer.Core.Infrastructure; -//TODO(Lilla): refactor so it is longer using proxy based calling +//TODO(Lilla): refactor so it is longer using proxy based callings internal class Communicator : ICommunicator { private IProcessInfoAggregator _aggregator; diff --git a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Core/ProcessInfoAggregator.cs b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Core/ProcessInfoAggregator.cs index 0e876a5d5..cb31a8b7a 100644 --- a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Core/ProcessInfoAggregator.cs +++ b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Core/ProcessInfoAggregator.cs @@ -40,6 +40,8 @@ internal class ProcessInfoAggregator : IProcessInfoAggregator private readonly object _uiClientLock = new(); private bool _disposed; + public int MainProcessId { get; private set; } + public ProcessInfoAggregator( ILogger? logger, ProcessInfoManager processInfoManager, @@ -67,6 +69,12 @@ public async Task RunSubsystemStateQueue(CancellationToken cancellationToken) if (succeed) await ModifySubsystemState(subsystemInfo.Key, subsystemInfo.Value); } + + if (cancellationToken.IsCancellationRequested) + { + // Perform any cleanup actions here + break; + } } } @@ -96,17 +104,18 @@ public void RemoveRuntimeInformation(string assembly) } } - public void SetComposePid(int pid) + public void SetMainProcessId(int processId) { - _processInfoManager?.SetComposePid(pid); + MainProcessId = processId; + _processInfoManager.SetComposePid(processId); } private void SetUiCommunicatorsToWatchProcessChanges() { _processInfoManager.SetHandlers( ProcessModified, - ProcessCreated, ProcessTerminated, + ProcessCreated, ProcessesModified, ProcessStatusChanged); } @@ -138,9 +147,9 @@ private void ProcessesModified(ReadOnlySpan ids) } } - private void ProcessTerminated(int pid) + private void ProcessTerminated(int processId) { - _logger.ProcessTerminatedInformation(pid); + _logger.ProcessTerminatedInformation(processId); lock (_uiClientLock) { @@ -148,19 +157,19 @@ private void ProcessTerminated(int pid) foreach (var client in _uiClients.Values) { - client.TerminateProcess(pid); + client.TerminateProcess(processId); if (processes.Any()) client.AddProcesses(processes); } } } - private void ProcessCreated(int pid) + private void ProcessCreated(int processId) { - var process = GetProcess(pid); + var process = GetProcess(processId); if (process.Equals(default)) return; - _logger.ProcessCreatedInformation(pid); + _logger.ProcessCreatedInformation(processId); lock (_uiClientLock) { @@ -171,21 +180,21 @@ private void ProcessCreated(int pid) } } - private ProcessInfoData? GetProcess(int pid) + private ProcessInfoData? GetProcess(int processId) { - var process = GetProcesses(_processInfoManager.GetProcessIds()).FirstOrDefault(proc => proc.PID == pid); + var process = GetProcesses(_processInfoManager.GetProcessIds()).FirstOrDefault(proc => proc.ProcessId == processId); if (process.Equals(default)) return null; return process; } - private void ProcessModified(int pid) + private void ProcessModified(int processId) { - var process = GetProcess(pid); + var process = GetProcess(processId); if (process.Equals(default)) return; - _logger.ProcessModifiedDebug(pid); + _logger.ProcessModifiedDebug(processId); lock (_uiClientLock) { @@ -221,11 +230,24 @@ public void AddUiConnection(Guid id, IUIHandler uiHandler) if (!success) return; - ProcessesModified(_processInfoManager.GetProcessIds()); - uiHandler.AddRuntimeInfo(_processInformation); + var processsIds = _processInfoManager.GetProcessIds(); + if(processsIds.Length > 0) + { + ProcessesModified(processsIds); + } + + lock (_processsInformationLock) + { + if(_processInformation.Any()) + uiHandler.AddRuntimeInfo(_processInformation); + } if (_subsystemController != null) - uiHandler.AddSubsystems(_subsystemController.GetSubsystems()); + { + var subsystems = _subsystemController.GetSubsystems(); + if(subsystems.Any()) + uiHandler.AddSubsystems(subsystems); + } _logger.ProcessMonitorCommunicatorIsSetDebug(); } @@ -367,10 +389,10 @@ public void DisableWatchingProcesses() _processInfoManager.Dispose(); } - public void InitProcesses(ReadOnlySpan pids) + public void InitProcesses(ReadOnlySpan processIds) { _processInfoManager.ClearProcessIds(); - _processInfoManager.SetProcessIds(pids); + _processInfoManager.SetProcessIds(processIds); } private Task UpdateInfoOnUI(Func handlerAction) @@ -427,9 +449,10 @@ public Task ModifySubsystemState(Guid subsystemId, string state) return _subsystemController.ModifySubsystemState(subsystemId, state); } - public void SetSubsystemController(ISubsystemController subsystemController) + public async void SetSubsystemController(ISubsystemController subsystemController) { _subsystemController = subsystemController; + _subsystemController.SetUiDelegate(UpdateInfoOnUI); } public void Dispose() diff --git a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Core/Processes/ProcessInformation.cs b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Core/Processes/ProcessInformation.cs index 0239ba437..8442aad53 100644 --- a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Core/Processes/ProcessInformation.cs +++ b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Core/Processes/ProcessInformation.cs @@ -33,22 +33,11 @@ private set } } - public ProcessInformation( - string name, - int pid) - { - _processInfo = new ProcessInfoData() - { - PID = pid, - ProcessName = name, - }; - } - public ProcessInformation(Process process) { _processInfo = new() { - PID = process.Id, + ProcessId = process.Id, ProcessName = process.ProcessName, }; } @@ -64,7 +53,7 @@ internal static void SetProcessInfoData(ref ProcessInformation processInfo, Proc { try { - var process = Process.GetProcessById(processInfo.ProcessInfo.PID!); + var process = Process.GetProcessById(processInfo.ProcessInfo.ProcessId!); process.Refresh(); processInfo._processInfo.PriorityLevel = process.BasePriority; diff --git a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Core/Subsystems/SubsystemController.cs b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Core/Subsystems/SubsystemController.cs index 5c9ecc9e9..2731b51f9 100644 --- a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Core/Subsystems/SubsystemController.cs +++ b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Core/Subsystems/SubsystemController.cs @@ -53,6 +53,7 @@ public SubsystemController( public async Task InitializeSubsystems(IEnumerable> subsystems) { UpdateOrAddElements(subsystems); + await SendModifiedSubsystems(); await LaunchSubsystemsAutomatically(); } diff --git a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Logging/SourceGeneratedLoggerExtensions.cs b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Logging/SourceGeneratedLoggerExtensions.cs index 658091203..64d183285 100644 --- a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Logging/SourceGeneratedLoggerExtensions.cs +++ b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Logging/SourceGeneratedLoggerExtensions.cs @@ -96,6 +96,9 @@ internal static partial class SourceGeneratedLoggerExtensions [LoggerMessage(Level = LogLevel.Error, Message = "Error while setting up process explorer server. Detailed exception: {exception}...", SkipEnabledCheck = false)] public static partial void ProcessExplorerSetupError(this ILogger logger, Exception ex, Exception exception); + [LoggerMessage(Level = LogLevel.Error, Message = "Error while setting up process explorer server-client subsription. Detailed exception: {exception}...", SkipEnabledCheck = false)] + public static partial void SubscriptionError(this ILogger logger, Exception ex, Exception exception); + //Warnings [LoggerMessage(Level = LogLevel.Warning, Message = "No timeout was declared while using CancellationToken for gRPC server...", SkipEnabledCheck = false)] public static partial void GrpcCancellationTokenWarning(this ILogger logger); diff --git a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/ProcessExplorer.Server.csproj b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/ProcessExplorer.Server.csproj index 1fee092e5..e20842b67 100644 --- a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/ProcessExplorer.Server.csproj +++ b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/ProcessExplorer.Server.csproj @@ -6,10 +6,6 @@ enable - - - - @@ -19,16 +15,10 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - diff --git a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Server/Abstractions/ProcessExplorerServer.cs b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Server/Abstractions/ProcessExplorerServer.cs index 58b587c92..6eabad2db 100644 --- a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Server/Abstractions/ProcessExplorerServer.cs +++ b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Server/Abstractions/ProcessExplorerServer.cs @@ -44,7 +44,7 @@ internal void SetupProcessExplorer( if (options.Value.Processes != null) { var processes = options.Value.Processes - .Select(process => process.ProcessInfo.PID) + .Select(process => process.ProcessInfo.ProcessId) .ToArray(); if (processes != null) processInfoAggregator.InitProcesses(processes); @@ -62,7 +62,7 @@ internal void SetupProcessExplorer( } if(options.Value.MainProcessId != null) - processInfoAggregator.SetComposePid((int)options.Value.MainProcessId); + processInfoAggregator.SetMainProcessId((int)options.Value.MainProcessId); if (options.Value.EnableProcessExplorer) processInfoAggregator.EnableWatchingSavedProcesses(); diff --git a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Server/GrpcServer/GrpcListenerService.cs b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Server/GrpcServer/GrpcListenerService.cs index 633ab4410..a59702bb4 100644 --- a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Server/GrpcServer/GrpcListenerService.cs +++ b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Server/GrpcServer/GrpcListenerService.cs @@ -16,12 +16,12 @@ using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using ProcessExplorer.Abstractions; +using ProcessExplorer.Abstractions.Infrastructure.Protos; using ProcessExplorer.Abstractions.Subsystems; using ProcessExplorer.Core.Factories; using ProcessExplorer.Server.Logging; using ProcessExplorer.Server.Server.Abstractions; using ProcessExplorer.Server.Server.Infrastructure.Grpc; -using ProcessExplorer.Server.Server.Infrastructure.Protos; using GRPCServer = Grpc.Core.Server; namespace ProcessExplorer.Server.Server.GrpcServer; @@ -32,6 +32,7 @@ internal class GrpcListenerService : ProcessExplorerServer, IHostedService private readonly ProcessExplorerServerOptions _options; private readonly ILogger _logger; private GRPCServer? _grpcServer; + private CancellationToken _cancellationToken; public GrpcListenerService( IProcessInfoAggregator processInfoAggregator, @@ -62,10 +63,14 @@ public Task StartAsync(CancellationToken cancellationToken) { if (cancellationToken == CancellationToken.None) _logger.GrpcCancellationTokenWarning(); - Task.Run(() => StartAsyncCore()); - Task.Run(() => _processInfoAggregator.RunSubsystemStateQueue(cancellationToken)); + _cancellationToken = cancellationToken; - return Task.CompletedTask; + var serverTask = Task.Run(() => StartAsyncCore()); + + var queueCts = CancellationTokenSource.CreateLinkedTokenSource(_cancellationToken); + var queueTask = Task.Run(() => _processInfoAggregator.RunSubsystemStateQueue(queueCts.Token), queueCts.Token); + + return Task.WhenAny(serverTask, queueTask); } private void StartAsyncCore() @@ -77,6 +82,12 @@ private void StartAsyncCore() _grpcServer.Start(); SetupProcessExplorer(_options, _processInfoAggregator); + + _cancellationToken.Register(() => + { + _logger.GrpcServerStoppedDebug(); + _grpcServer.ShutdownAsync().Wait(); + }); } private void SetupGrpcServer() @@ -90,8 +101,8 @@ private void SetupGrpcServer() public async Task StopAsync(CancellationToken cancellationToken) { + if (_grpcServer == null) return; + _processInfoAggregator.Dispose(); _logger.GrpcServerStoppedDebug(); - - if(_grpcServer != null) await _grpcServer.ShutdownAsync(); } } diff --git a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Server/Helper/ProtoConvertHelper.cs b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Server/Helper/ProtoConvertHelper.cs index c32c9c916..1dc250eff 100644 --- a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Server/Helper/ProtoConvertHelper.cs +++ b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Server/Helper/ProtoConvertHelper.cs @@ -15,9 +15,10 @@ using Google.Protobuf.WellKnownTypes; using LocalCollector.Connections; using ProcessExplorer.Abstractions.Extensions; +using ProcessExplorer.Abstractions.Infrastructure.Protos; using ProcessExplorer.Abstractions.Processes; using ProcessExplorer.Abstractions.Subsystems; -using ProcessExplorer.Server.Server.Infrastructure.Protos; +using Process = ProcessExplorer.Abstractions.Infrastructure.Protos.Process; namespace ProcessExplorer.Server.Server.Helper; @@ -54,16 +55,13 @@ public static Process DeriveProtoProcessType(this ProcessInfoData process) return new() { - InstanceId = string.Empty, - UiType = string.Empty, - UiHint = string.Empty, StartTime = process.StartTime ?? string.Empty, ProcessorUsageTime = process.ProcessorUsageTime != null ? Duration.FromTimeSpan((TimeSpan)process.ProcessorUsageTime) : Duration.FromTimeSpan(TimeSpan.Zero), PhysicalMemoryUsageBit = process.PhysicalMemoryUsageBit ?? 0, ProcessName = process.ProcessName ?? string.Empty, - Pid = process.PID, + Pid = process.ProcessId, ProcessPriorityClass = process.ProcessPriorityClass ?? string.Empty, Threads = { threads }, VirtualMemorySize = process.VirtualMemorySize ?? 0, diff --git a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Server/Infrastructure/Grpc/GrpcUIHandler.cs b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Server/Infrastructure/Grpc/GrpcUIHandler.cs index 523f450a4..2f766edee 100644 --- a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Server/Infrastructure/Grpc/GrpcUIHandler.cs +++ b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Server/Infrastructure/Grpc/GrpcUIHandler.cs @@ -18,11 +18,11 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using ProcessExplorer.Abstractions.Infrastructure; +using ProcessExplorer.Abstractions.Infrastructure.Protos; using ProcessExplorer.Abstractions.Processes; using ProcessExplorer.Abstractions.Subsystems; using ProcessExplorer.Server.Logging; using ProcessExplorer.Server.Server.Helper; -using ProcessExplorer.Server.Server.Infrastructure.Protos; namespace ProcessExplorer.Server.Server.Infrastructure.Grpc; @@ -30,14 +30,14 @@ internal class GrpcUIHandler : IUIHandler { private readonly object _lock = new(); private readonly ILogger _logger; - private readonly KeyValuePair> stream; + private readonly KeyValuePair> _stream; public GrpcUIHandler( IServerStreamWriter responseStream, Guid id, ILogger? logger) { _logger = logger ?? NullLogger.Instance; - stream = new(id, responseStream); + _stream = new(id, responseStream); } public Task AddConnections(string assemblyId, IEnumerable connections) @@ -52,7 +52,7 @@ public Task AddConnections(string assemblyId, IEnumerable connec }; lock (_lock) - return stream.Value.WriteAsync(message); + return _stream.Value.WriteAsync(message); } catch (Exception exception) { @@ -78,7 +78,7 @@ public Task AddProcess(ProcessInfoData process) }; lock (_lock) - return stream.Value.WriteAsync(message); + return _stream.Value.WriteAsync(message); } catch (Exception exception) { @@ -99,7 +99,7 @@ public Task AddProcesses(IEnumerable processes) }; lock (_lock) - return stream.Value.WriteAsync(message); + return _stream.Value.WriteAsync(message); } catch (Exception exception) { @@ -126,7 +126,7 @@ public Task AddRuntimeInfo(string assemblyId, LocalCollector.ProcessInfoCollecto }; lock (_lock) - return stream.Value.WriteAsync(message); + return _stream.Value.WriteAsync(message); } catch (Exception exception) { @@ -147,7 +147,7 @@ public Task AddRuntimeInfo(IEnumerable modules) }; lock (_lock) - return stream.Value.WriteAsync(message); + return _stream.Value.WriteAsync(message); } catch (Exception exception) { @@ -264,7 +264,7 @@ public Task UpdateProcess(ProcessInfoData process) }; lock (_lock) - return stream.Value.WriteAsync(message); + return _stream.Value.WriteAsync(message); } catch (Exception exception) { @@ -286,7 +286,7 @@ public Task UpdateRegistrations(string assemblyId, IEnumerable }; lock (_lock) - return stream.Value.WriteAsync(message); + return _stream.Value.WriteAsync(message); } catch (Exception exception) { @@ -312,7 +312,7 @@ public Task AddSubsystem(Guid subsystemId, SubsystemInfo subsystem) }; lock (_lock) - return stream.Value.WriteAsync(message); + return _stream.Value.WriteAsync(message); } catch (Exception exception) { @@ -333,7 +333,7 @@ public Task AddSubsystems(IEnumerable> subsyst }; lock (_lock) - return stream.Value.WriteAsync(message); + return _stream.Value.WriteAsync(message); } catch (Exception exception) { @@ -359,7 +359,7 @@ public Task UpdateSubsystemInfo(Guid subsystemId, SubsystemInfo subsystem) }; lock (_lock) - return stream.Value.WriteAsync(message); + return _stream.Value.WriteAsync(message); } catch (Exception exception) { @@ -385,7 +385,7 @@ public Task UpdateProcessStatus(KeyValuePair responseStream, ServerCallContext context) + public override async Task Subscribe(Empty request, IServerStreamWriter responseStream, ServerCallContext context) { var id = Guid.NewGuid(); _logger.GrpcClientSubscribedDebug(id.ToString()); @@ -43,6 +43,7 @@ public override Task Subscribe(Empty request, IServerStreamWriter respo try { + await handler.SubscriptionIsAliveUpdate(); _processInfoAggregator.AddUiConnection(id, handler); //wait here until the user is alive @@ -57,8 +58,6 @@ public override Task Subscribe(Empty request, IServerStreamWriter respo { _processInfoAggregator.RemoveUiConnection(new(id, handler)); } - - return Task.CompletedTask; } public override Task Send(Message request, ServerCallContext context) diff --git a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Server/MessageHandler.cs b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Server/MessageHandler.cs index e7d30b61f..6070829f8 100644 --- a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Server/MessageHandler.cs +++ b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/src/ProcessExplorer.Server/Server/MessageHandler.cs @@ -12,8 +12,8 @@ using Microsoft.Extensions.Logging; using ProcessExplorer.Abstractions; +using ProcessExplorer.Abstractions.Infrastructure.Protos; using ProcessExplorer.Server.Logging; -using ProcessExplorer.Server.Server.Infrastructure.Protos; namespace ProcessExplorer.Server.Server; diff --git a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/test/ProcessExplorer.Core.Tests/ProcessInfoAggregator.Tests.cs b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/test/ProcessExplorer.Core.Tests/ProcessInfoAggregator.Tests.cs index 30f8849ca..1241bfd3b 100644 --- a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/test/ProcessExplorer.Core.Tests/ProcessInfoAggregator.Tests.cs +++ b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/test/ProcessExplorer.Core.Tests/ProcessInfoAggregator.Tests.cs @@ -1,9 +1,11 @@ using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Reflection; using System.Threading; using System.Threading.Tasks; using LocalCollector; +using LocalCollector.Connections; using Microsoft.Extensions.Logging.Abstractions; using Moq; using ProcessExplorer.Abstractions; @@ -15,6 +17,7 @@ namespace ProcessExplorer.Core.Tests; +//End to end tests server and just send messages, also mock, and test windowsprocess with creating process release/debug folder public class ProcessInfoAggregatorTests { [Fact] @@ -49,7 +52,7 @@ public async Task RunSubsystemQueue_will_cancel_after_timeout() Assert.True(cancellationTokenSource.IsCancellationRequested); } - [Fact(Skip = "Run in Windows environment")] + [Fact(Skip = "Run in Windows environment")] //nem szuksegss public void SetComposePid_will_set_the_main_id() { //Creating mocks to handle method @@ -67,7 +70,7 @@ public void SetComposePid_will_set_the_main_id() processInfoManager, mockSubsystemController.Object); - processInfoAggregator.SetComposePid(dummyPid); + processInfoAggregator.SetMainProcessId(dummyPid); //using reflection to compare values var field = typeof(ProcessInfoManager).GetField("_composePid", BindingFlags.NonPublic | BindingFlags.Instance); @@ -256,12 +259,12 @@ public async Task RemoveRuntimeInformation_will_remove_item_from_collection() Assert.Single(collection); } - //[Theory] - //[ClassData(typeof(ConnectionTheoryData))] - //public async Task AddConnectionCollection_will_add_a_new_connection_collection_information(string id, IEnumerable connections) - //{ + [Theory] + [ClassData(typeof(ConnectionTheoryData))] + public async Task AddConnectionCollection_will_add_a_new_connection_collection_information(string id, IEnumerable connections) + { - //} + } //[Fact] //public async Task AddConnectionCollection_will_update_connection_collection_information(string id, IEnumerable connections) diff --git a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/test/ProcessExplorer.Server.EndToEndTests/EndToEndTests.cs b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/test/ProcessExplorer.Server.EndToEndTests/EndToEndTests.cs new file mode 100644 index 000000000..64da4d1ce --- /dev/null +++ b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/test/ProcessExplorer.Server.EndToEndTests/EndToEndTests.cs @@ -0,0 +1,180 @@ +// Morgan Stanley makes this available to you under the Apache License, +// Version 2.0 (the "License"). You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0. +// +// See the NOTICE file distributed with this work for additional information +// regarding copyright ownership. Unless required by applicable law or agreed +// to in writing, software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +// or implied. See the License for the specific language governing permissions +// and limitations under the License. + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Google.Protobuf.WellKnownTypes; +using Grpc.Core; +using Grpc.Net.Client; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using ProcessExplorer.Abstractions; +using ProcessExplorer.Abstractions.Infrastructure.Protos; +using ProcessExplorer.Abstractions.Subsystems; +using ProcessExplorer.Server.DependencyInjection; +using ProcessExplorer.Server.Server.Abstractions; +using Xunit; +using FluentAssertions.Execution; +using FluentAssertions; + +namespace ProcessExplorer.Server.IntegrationTests; + +public class EndToEndTests : IAsyncLifetime +{ + private IHost? _host; + public readonly string Host = "localhost"; + public readonly int Port = 5056; + + public async Task DisposeAsync() + { + if (_host != null) + await _host.StopAsync(); + } + + [Fact] + public async Task Client_can_connect() + { + var channel = GrpcChannel.ForAddress($"http://{Host}:{Port}/"); + var client = new ProcessExplorerMessageHandler.ProcessExplorerMessageHandlerClient(channel); + + using var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(1)); + + var messages = new List(); + + var call = client.Subscribe(new Empty(), null, null, cancellationTokenSource.Token); + + // We want to receive the message, that the subscription is estabilished, and we do not want to wait. + // Due to that no processes/subsystems/runtime information have not been declared it will just receive the subscription alive notification + await foreach (var message in call.ResponseStream.ReadAllAsync()) + { + messages.Add(message); + break; + } + + messages.Count.Should().Be(1); + messages[0].Action.Should().Be(ActionType.SubscriptionAliveAction); + } + + [Fact] + public async Task Client_can_subscribe_and_receive_messages() + { + // defining here some dummy subsystems to trigger the ProcessExplorer backend to send information about it to the defined ui connections. (not just the subscription alive notification) + var aggregator = _host?.Services.GetRequiredService(); + + var dummyId = Guid.NewGuid(); + + var dummySubsystemInfo = new SubsystemInfo() + { + State = SubsystemState.Running, + Name = "DummySubsystem", + UIType = "dummy", + StartupType = "dummy", + Path = "dummyPath", + AutomatedStart = false, + }; + + var subsystems = new Dictionary() + { + { dummyId, dummySubsystemInfo } + }; + + if (aggregator != null) + { + await aggregator.InitializeSubsystems(subsystems); + } + + var channel = GrpcChannel.ForAddress($"http://{Host}:{Port}/"); + var client = new ProcessExplorerMessageHandler.ProcessExplorerMessageHandlerClient(channel); + var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(1)); + var messages = new List(); + + var call = client.Subscribe(new Empty(), null, null, cancellationTokenSource.Token); + + //try catch block to avoid OperationCanceledException due to that we are just waiting for 1 second + try + { + await foreach (var message in call.ResponseStream.ReadAllAsync()) + { + messages.Add(message); + } + } + catch(RpcException) { } + + // We just need to receive SubscriptionAlive and a subsystems collection + messages.Count.Should().Be(2); + messages[0].Action.Should().Be(ActionType.SubscriptionAliveAction); + messages[1].Action.Should().Be(ActionType.AddSubsystemsAction); + messages[1].Subsystems.Count.Should().Be(1); + messages[1].Subsystems.Should().ContainKey(dummyId.ToString()); + + var result = messages[1].Subsystems[dummyId.ToString()]; + result.Should().NotBeNull(); + result.Name.Should().BeEquivalentTo(dummySubsystemInfo.Name); + } + + [Fact] + public void Client_can_send_message() + { + var channel = GrpcChannel.ForAddress($"http://{Host}:{Port}/"); + var client = new ProcessExplorerMessageHandler.ProcessExplorerMessageHandlerClient(channel); + var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(1)); + + var message = new Message() + { + Action = ActionType.SubscriptionAliveAction, + Description = "dummy message" + }; + + var act = () => client.Send(message, cancellationToken: cancellationTokenSource.Token); + act.Should().NotThrow(); + + var result = client.Send(message, cancellationToken: cancellationTokenSource.Token); + result.Should().BeOfType(); + } + + public async Task InitializeAsync() + { + IHostBuilder builder = new HostBuilder(); + + builder.ConfigureServices( + (context, services) => services + .AddProcessExplorerWindowsServer(pe => pe.UseGrpc()) + .ConfigureSubsystemLauncher(Start, Stop, CreateDummyStartType, CreateDummyStopType) + .Configure(op => + { + op.Host = Host; + op.Port = Port; + })); + + _host = builder.Build(); + await _host.StartAsync(); + } + + + private static DummyStartType CreateDummyStartType(Guid id, string name) + { + return new DummyStartType(id, name); + } + + private static DummyStopType CreateDummyStopType(Guid id) + { + return new DummyStopType(id); + } + + private static void Start(DummyStartType dummy) { } + private static void Stop(DummyStopType dummy) { } + + private record DummyStartType(Guid id, string name); + private record DummyStopType(Guid id); +} diff --git a/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/test/ProcessExplorer.Server.EndToEndTests/ProcessExplorer.Server.IntegrationTests.csproj b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/test/ProcessExplorer.Server.EndToEndTests/ProcessExplorer.Server.IntegrationTests.csproj new file mode 100644 index 000000000..87ee02be5 --- /dev/null +++ b/Tryouts/Plugins/ApplicationPlugins/MorganStanley.ComposeUI.ProcessExplorer/dotnet/test/ProcessExplorer.Server.EndToEndTests/ProcessExplorer.Server.IntegrationTests.csproj @@ -0,0 +1,32 @@ + + + + net6.0 + enable + + false + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + +