public async Task <ServerSourceHolder> StartServerAsync(EndpointInfoSourceCallback sourceCallback = null, IDumpService dumpService = null, OperationTrackerService operationTrackerService = null) { DiagnosticPortHelper.Generate(DiagnosticPortConnectionMode.Listen, out _, out string transportName); _outputHelper.WriteLine("Starting server endpoint info source at '" + transportName + "'."); List <IEndpointInfoSourceCallbacks> callbacks = new(); if (null != sourceCallback) { callbacks.Add(sourceCallback); if (null != dumpService) { callbacks.Add(new OperationTrackerServiceEndpointInfoSourceCallback(operationTrackerService)); } } IOptions <DiagnosticPortOptions> portOptions = Extensions.Options.Options.Create( new DiagnosticPortOptions() { ConnectionMode = DiagnosticPortConnectionMode.Listen, EndpointName = transportName }); ServerEndpointInfoSource source = new(portOptions, callbacks, operationTrackerService); await source.StartAsync(CancellationToken.None); return(new ServerSourceHolder(source, transportName)); }
public async Task CollectionRule_ConfigurationChangeTest(DiagnosticPortConnectionMode mode) { const string firstRuleName = "FirstRule"; const string secondRuleName = "SecondRule"; DiagnosticPortHelper.Generate( mode, out DiagnosticPortConnectionMode appConnectionMode, out string diagnosticPortPath); await using MonitorCollectRunner toolRunner = new(_outputHelper); toolRunner.ConnectionMode = mode; toolRunner.DiagnosticPortPath = diagnosticPortPath; toolRunner.DisableAuthentication = true; // Create a rule with some settings RootOptions originalOptions = new(); originalOptions.CreateCollectionRule(firstRuleName) .SetStartupTrigger(); await toolRunner.WriteUserSettingsAsync(originalOptions); await toolRunner.StartAsync(); AppRunner appRunner = new(_outputHelper, Assembly.GetExecutingAssembly()); appRunner.ConnectionMode = appConnectionMode; appRunner.DiagnosticPortPath = diagnosticPortPath; appRunner.ScenarioName = TestAppScenarios.AsyncWait.Name; Task originalActionsCompletedTask = toolRunner.WaitForCollectionRuleActionsCompletedAsync(firstRuleName); await appRunner.ExecuteAsync(async() => { // Validate that the first rule is observed and its actions are run. await originalActionsCompletedTask; // Set up new observers for the first and second rule. originalActionsCompletedTask = toolRunner.WaitForCollectionRuleActionsCompletedAsync(firstRuleName); Task newActionsCompletedTask = toolRunner.WaitForCollectionRuleActionsCompletedAsync(secondRuleName); // Change collection rule configuration to only contain the second rule. RootOptions newOptions = new(); newOptions.CreateCollectionRule(secondRuleName) .SetStartupTrigger(); await toolRunner.WriteUserSettingsAsync(newOptions); // Validate that only the second rule is observed. await newActionsCompletedTask; Assert.False(originalActionsCompletedTask.IsCompleted); await appRunner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue); }); Assert.Equal(0, appRunner.ExitCode); }
public async Task CollectionRule_StoppedOnExitTest(DiagnosticPortConnectionMode mode) { DiagnosticPortHelper.Generate( mode, out DiagnosticPortConnectionMode appConnectionMode, out string diagnosticPortPath); await using MonitorCollectRunner toolRunner = new(_outputHelper); toolRunner.ConnectionMode = mode; toolRunner.DiagnosticPortPath = diagnosticPortPath; toolRunner.DisableAuthentication = true; // Create a rule with some settings RootOptions originalOptions = new(); originalOptions.CreateCollectionRule(DefaultRuleName) .SetEventCounterTrigger(options => { options.ProviderName = "System.Runtime"; options.CounterName = "cpu-usage"; options.GreaterThan = 1000; // Intentionally unobtainable options.SlidingWindowDuration = TimeSpan.FromSeconds(1); }); await toolRunner.WriteUserSettingsAsync(originalOptions); await toolRunner.StartAsync(); AppRunner appRunner = new(_outputHelper, Assembly.GetExecutingAssembly()); appRunner.ConnectionMode = appConnectionMode; appRunner.DiagnosticPortPath = diagnosticPortPath; appRunner.ScenarioName = TestAppScenarios.AsyncWait.Name; Task ruleStartedTask = toolRunner.WaitForCollectionRuleStartedAsync(DefaultRuleName); Task rulesStoppedTask = toolRunner.WaitForCollectionRulesStoppedAsync(); await appRunner.ExecuteAsync(async() => { await ruleStartedTask; await appRunner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue); }); Assert.Equal(0, appRunner.ExitCode); // All of the rules for the process should have stopped. Note that dotnet-monitor has // not yet exited at this point in time; this is verification that the rules have stopped // for the target process before dotnet-monitor shuts down. await rulesStoppedTask; }
public static async Task SingleTarget( ITestOutputHelper outputHelper, IHttpClientFactory httpClientFactory, DiagnosticPortConnectionMode mode, string scenarioName, Func <AppRunner, ApiClient, Task> appValidate, Func <ApiClient, int, Task> postAppValidate = null, Action <AppRunner> configureApp = null, Action <MonitorCollectRunner> configureTool = null, bool disableHttpEgress = false) { DiagnosticPortHelper.Generate( mode, out DiagnosticPortConnectionMode appConnectionMode, out string diagnosticPortPath); await using MonitorCollectRunner toolRunner = new(outputHelper); toolRunner.ConnectionMode = mode; toolRunner.DiagnosticPortPath = diagnosticPortPath; toolRunner.DisableAuthentication = true; toolRunner.DisableHttpEgress = disableHttpEgress; configureTool?.Invoke(toolRunner); await toolRunner.StartAsync(); using HttpClient httpClient = await toolRunner.CreateHttpClientDefaultAddressAsync(httpClientFactory); ApiClient apiClient = new(outputHelper, httpClient); AppRunner appRunner = new(outputHelper, Assembly.GetExecutingAssembly()); appRunner.ConnectionMode = appConnectionMode; appRunner.DiagnosticPortPath = diagnosticPortPath; appRunner.ScenarioName = scenarioName; configureApp?.Invoke(appRunner); await appRunner.ExecuteAsync(async() => { await appValidate(appRunner, apiClient); }); Assert.Equal(0, appRunner.ExitCode); if (null != postAppValidate) { await postAppValidate(apiClient, await appRunner.ProcessIdTask); } }
public async Task MultiProcessIdentificationTest(DiagnosticPortConnectionMode mode) { DiagnosticPortHelper.Generate( mode, out DiagnosticPortConnectionMode appConnectionMode, out string diagnosticPortPath); await using MonitorCollectRunner toolRunner = new(_outputHelper); toolRunner.ConnectionMode = mode; toolRunner.DiagnosticPortPath = diagnosticPortPath; toolRunner.DisableAuthentication = true; await toolRunner.StartAsync(); using HttpClient httpClient = await toolRunner.CreateHttpClientDefaultAddressAsync(_httpClientFactory); ApiClient apiClient = new(_outputHelper, httpClient); const int appCount = 3; AppRunner[] appRunners = new AppRunner[appCount]; for (int i = 0; i < appCount; i++) { AppRunner runner = new(_outputHelper, Assembly.GetExecutingAssembly(), appId : i + 1); runner.ConnectionMode = appConnectionMode; runner.DiagnosticPortPath = diagnosticPortPath; runner.ScenarioName = TestAppScenarios.AsyncWait.Name; runner.Environment[ExpectedEnvVarName] = Guid.NewGuid().ToString("D"); appRunners[i] = runner; } IList <ProcessIdentifier> identifiers; await appRunners.ExecuteAsync(async() => { // Scope to only the processes that were launched by the test IList <int> unmatchedPids = new List <int>(); foreach (AppRunner runner in appRunners) { unmatchedPids.Add(await runner.ProcessIdTask); } // Query for process identifiers identifiers = (await apiClient.GetProcessesWithRetryAsync( _outputHelper, unmatchedPids.ToArray())).ToList(); Assert.NotNull(identifiers); _outputHelper.WriteLine("Start enumerating discovered processes."); foreach (ProcessIdentifier identifier in identifiers.ToList()) { _outputHelper.WriteLine($"- PID: {identifier.Pid}"); _outputHelper.WriteLine($" UID: {identifier.Uid}"); _outputHelper.WriteLine($" Name: {identifier.Name}"); unmatchedPids.Remove(identifier.Pid); } _outputHelper.WriteLine("End enumerating discovered processes"); Assert.Empty(unmatchedPids); Assert.Equal(appRunners.Length, identifiers.Count); foreach (ProcessIdentifier processIdentifier in identifiers) { int pid = processIdentifier.Pid; Guid uid = processIdentifier.Uid; string name = processIdentifier.Name; #if NET5_0_OR_GREATER // CHECK 1: Get response for processes using PID, UID, and Name and check for consistency List <ProcessInfo> processInfoQueriesCheck1 = new List <ProcessInfo>(); processInfoQueriesCheck1.Add(await apiClient.GetProcessWithRetryAsync(_outputHelper, pid: pid)); // Only check with uid if it is non-empty; this can happen in connect mode if the ProcessInfo command fails // to respond within the short period of time that is used to get the additional process information. if (uid == Guid.Empty) { _outputHelper.WriteLine("Skipped uid-only check because it is empty GUID."); } else { processInfoQueriesCheck1.Add(await apiClient.GetProcessWithRetryAsync(_outputHelper, uid: uid)); } VerifyProcessInfoEquality(processInfoQueriesCheck1); #endif // CHECK 2: Get response for requests using PID | PID and UID | PID, UID, and Name and check for consistency List <ProcessInfo> processInfoQueriesCheck2 = new List <ProcessInfo>(); processInfoQueriesCheck2.Add(await apiClient.GetProcessWithRetryAsync(_outputHelper, pid: pid)); processInfoQueriesCheck2.Add(await apiClient.GetProcessWithRetryAsync(_outputHelper, pid: pid, uid: uid)); processInfoQueriesCheck2.Add(await apiClient.GetProcessWithRetryAsync(_outputHelper, pid: pid, uid: uid, name: name)); VerifyProcessInfoEquality(processInfoQueriesCheck2); // CHECK 3: Get response for processes using PID and an unassociated (randomly generated) UID and ensure the proper exception is thrown await VerifyInvalidRequestException(apiClient, pid, Guid.NewGuid(), null); } // CHECK 4: Get response for processes using invalid PID, UID, or Name and ensure the proper exception is thrown await VerifyInvalidRequestException(apiClient, -1, null, null); await VerifyInvalidRequestException(apiClient, null, Guid.NewGuid(), null); await VerifyInvalidRequestException(apiClient, null, null, ""); // Verify each app instance is reported and shut them down. foreach (AppRunner runner in appRunners) { Assert.True(runner.Environment.TryGetValue(ExpectedEnvVarName, out string expectedEnvVarValue)); await VerifyProcessAsync(apiClient, identifiers, await runner.ProcessIdTask, expectedEnvVarValue); await runner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue); } }); for (int i = 0; i < appCount; i++) { Assert.True(0 == appRunners[i].ExitCode, $"App {i} exit code is non-zero."); } // Query for process identifiers identifiers = (await apiClient.GetProcessesAsync()).ToList(); Assert.NotNull(identifiers); // Verify none of the apps are reported List <int> runnerProcessIds = new(appCount); for (int i = 0; i < appCount; i++) { runnerProcessIds.Add(await appRunners[i].ProcessIdTask); } foreach (ProcessIdentifier identifier in identifiers) { Assert.DoesNotContain(identifier.Pid, runnerProcessIds); } }