private async Task BasicProcessInfoTestCore(bool useAsync) { using TestRunner runner = new TestRunner(CommonHelper.GetTraceePathWithArgs(targetFramework: "net5.0"), output); runner.Start(); try { DiagnosticsClientApiShim clientShim = new DiagnosticsClientApiShim(new DiagnosticsClient(runner.Pid), useAsync); ProcessInfo processInfo = await clientShim.GetProcessInfo(); Assert.NotNull(processInfo); Assert.Equal(runner.Pid, (int)processInfo.ProcessId); Assert.NotNull(processInfo.CommandLine); Assert.NotNull(processInfo.OperatingSystem); Assert.NotNull(processInfo.ProcessArchitecture); //Assert.Equal("Tracee", processInfo.ManagedEntrypointAssemblyName); //Version clrVersion = ParseVersionRemoveLabel(processInfo.ClrProductVersionString); //Assert.True(clrVersion >= new Version(6, 0, 0)); } finally { runner.PrintStatus(); } }
/// <summary> /// Get process information with entrypoint information with exponential backoff on retries. /// </summary> private async Task <ProcessInfo> GetProcessInfoWithEntrypointAsync(DiagnosticsClientApiShim shim) { int retryMilliseconds = 5; int currentAttempt = 1; const int maxAttempts = 10; _output.WriteLine("Getting process info with entrypoint:"); while (currentAttempt <= maxAttempts) { _output.WriteLine("- Attempt {0} of {1}.", currentAttempt, maxAttempts); ProcessInfo processInfo = await shim.GetProcessInfo(); Assert.NotNull(processInfo); if (!string.IsNullOrEmpty(processInfo.ManagedEntrypointAssemblyName)) { _output.WriteLine("Got process info with entrypoint."); return(processInfo); } currentAttempt++; if (currentAttempt != maxAttempts) { _output.WriteLine(" Waiting {0} ms.", retryMilliseconds); await Task.Delay(retryMilliseconds); retryMilliseconds = Math.Min(2 * retryMilliseconds, 500); } } throw new InvalidOperationException("Unable to get process info with entrypoint."); }
/// <summary> /// Test for the method overload: public EventPipeSession StartEventPipeSession(EventPipeProvider provider, bool requestRundown=true, int circularBufferMB=256) /// </summary> private async Task StartEventPipeSessionWithSingleProviderTestCore(bool useAsync) { using TestRunner runner = new TestRunner(CommonHelper.GetTraceePathWithArgs(), output); runner.Start(timeoutInMSPipeCreation: 15_000, testProcessTimeout: 60_000); DiagnosticsClientApiShim clientShim = new DiagnosticsClientApiShim(new DiagnosticsClient(runner.Pid), useAsync); using (var session = await clientShim.StartEventPipeSession(new EventPipeProvider("Microsoft-Windows-DotNETRuntime", EventLevel.Informational))) { Assert.True(session.EventStream != null); } runner.Stop(); }
/// <summary> /// Tries to start an EventPipe session on a non-existent process /// </summary> private async Task EventPipeSessionUnavailableTestCore(bool useAsync) { List <int> pids = new List <int>(DiagnosticsClient.GetPublishedProcesses()); int arbitraryPid = 1; DiagnosticsClientApiShim clientShim = new DiagnosticsClientApiShim(new DiagnosticsClient(arbitraryPid), useAsync); await Assert.ThrowsAsync <ServerNotAvailableException>(() => clientShim.StartEventPipeSession(new List <EventPipeProvider>() { new EventPipeProvider("Microsoft-Windows-DotNETRuntime", EventLevel.Informational) })); }
private async Task BasicProcessInfoTestCore(bool useAsync, bool suspend) { using TestRunner runner = new TestRunner(CommonHelper.GetTraceePathWithArgs(targetFramework: "net5.0"), _output); if (suspend) { runner.SuspendDefaultDiagnosticPort(); } runner.Start(); try { DiagnosticsClientApiShim clientShim = new DiagnosticsClientApiShim(new DiagnosticsClient(runner.Pid), useAsync); // While suspended, the runtime will not provide entrypoint information. ProcessInfo processInfoBeforeResume = null; if (suspend) { processInfoBeforeResume = await clientShim.GetProcessInfo(); ValidateProcessInfo(runner.Pid, processInfoBeforeResume); Assert.True(string.IsNullOrEmpty(processInfoBeforeResume.ManagedEntrypointAssemblyName)); await clientShim.ResumeRuntime(); } // The entrypoint information is available some short time after the runtime // begins to execute. Retry getting process information until entrypoint is available. ProcessInfo processInfo = await GetProcessInfoWithEntrypointAsync(clientShim); ValidateProcessInfo(runner.Pid, processInfo); Assert.Equal("Tracee", processInfo.ManagedEntrypointAssemblyName); // Validate values before resume (except for entrypoint) are the same after resume. if (suspend) { Assert.Equal(processInfoBeforeResume.ProcessId, processInfo.ProcessId); Assert.Equal(processInfoBeforeResume.RuntimeInstanceCookie, processInfo.RuntimeInstanceCookie); Assert.Equal(processInfoBeforeResume.CommandLine, processInfo.CommandLine); Assert.Equal(processInfoBeforeResume.OperatingSystem, processInfo.OperatingSystem); Assert.Equal(processInfoBeforeResume.ProcessArchitecture, processInfo.ProcessArchitecture); Assert.Equal(processInfoBeforeResume.ClrProductVersionString, processInfo.ClrProductVersionString); } } finally { runner.PrintStatus(); } }
/// <summary> /// A simple test that collects process environment. /// </summary> private async Task BasicEnvTestCore(bool useAsync) { // as the attribute says, this test requires 5.0-rc1 or newer. This has been tested locally on // an rc1 build and passes. It is equivalent to the dotnet/runtime version of this test. using TestRunner runner = new TestRunner(CommonHelper.GetTraceePathWithArgs(targetFramework: "net5.0"), output); string testKey = "FOO"; string testVal = "BAR"; runner.AddEnvVar(testKey, testVal); runner.Start(timeoutInMSPipeCreation: 3000); var clientShim = new DiagnosticsClientApiShim(new DiagnosticsClient(runner.Pid), useAsync); Dictionary <string, string> env = await clientShim.GetProcessEnvironment(); Assert.True(env.ContainsKey(testKey) && env[testKey].Equals(testVal)); runner.Stop(); }
/// <summary> /// Checks if we can create an EventPipeSession and can get some expected events out of it. /// </summary> private async Task EventPipeSessionStreamTestCore(bool useAsync) { TestRunner runner = new TestRunner(CommonHelper.GetTraceePathWithArgs(), output); runner.Start(timeoutInMSPipeCreation: 15_000, testProcessTimeout: 60_000); DiagnosticsClientApiShim clientShim = new DiagnosticsClientApiShim(new DiagnosticsClient(runner.Pid), useAsync); runner.PrintStatus(); output.WriteLine($"[{DateTime.Now.ToString()}] Trying to start an EventPipe session on process {runner.Pid}"); using (var session = await clientShim.StartEventPipeSession(new List <EventPipeProvider>() { new EventPipeProvider("System.Runtime", EventLevel.Informational, 0, new Dictionary <string, string>() { { "EventCounterIntervalSec", "1" } }) })) { var evntCnt = 0; Task streamTask = Task.Run(() => { var source = new EventPipeEventSource(session.EventStream); source.Dynamic.All += (TraceEvent obj) => { output.WriteLine("Got an event"); evntCnt += 1; }; try { source.Process(); } catch (Exception e) { // This exception can happen if the target process exits while EventPipeEventSource is in the middle of reading from the pipe. output.WriteLine("Error encountered while processing events"); output.WriteLine(e.ToString()); } finally { runner.Stop(); } }); output.WriteLine("Waiting for stream Task"); streamTask.Wait(10000); output.WriteLine("Done waiting for stream Task"); Assert.True(evntCnt > 0); } }
private async Task ResumeRuntime(IpcEndpointInfo info, bool useAsync) { var clientShim = new DiagnosticsClientApiShim(new DiagnosticsClient(info.Endpoint), useAsync); _outputHelper.WriteLine($"{info.RuntimeInstanceCookie}: Resuming runtime instance."); try { await clientShim.ResumeRuntime(DefaultPositiveVerificationTimeout); _outputHelper.WriteLine($"{info.RuntimeInstanceCookie}: Resumed successfully."); } catch (ServerErrorException ex) { // Runtime likely does not understand the ResumeRuntime command. _outputHelper.WriteLine($"{info.RuntimeInstanceCookie}: {ex.Message}"); } }
/// <summary> /// Verifies that a client can handle multiple operations simultaneously. /// </summary> private async Task VerifySingleSession(IpcEndpointInfo info, bool useAsync) { await VerifyWaitForConnection(info, useAsync); var clientShim = new DiagnosticsClientApiShim(new DiagnosticsClient(info.Endpoint), useAsync); _outputHelper.WriteLine($"{info.RuntimeInstanceCookie}: Creating session #1."); var providers = new List <EventPipeProvider>(); providers.Add(new EventPipeProvider( "System.Runtime", EventLevel.Informational, 0, new Dictionary <string, string>() { { "EventCounterIntervalSec", "1" } })); using var session = await clientShim.StartEventPipeSession(providers); _outputHelper.WriteLine($"{info.RuntimeInstanceCookie}: Verifying session produces events."); await VerifyEventStreamProvidesEventsAsync(info, session, 1); _outputHelper.WriteLine($"{info.RuntimeInstanceCookie}: Session verification complete."); }
public static Task <EventPipeSession> StartEventPipeSession(this DiagnosticsClientApiShim shim, EventPipeProvider provider) { return(shim.StartEventPipeSession(provider, DefaultPositiveVerificationTimeout)); }
public static Task ResumeRuntime(this DiagnosticsClientApiShim shim) { return(shim.ResumeRuntime(DefaultPositiveVerificationTimeout)); }
public static Task <ProcessInfo> GetProcessInfo(this DiagnosticsClientApiShim shim) { return(shim.GetProcessInfo(DefaultPositiveVerificationTimeout)); }
public static Task <Dictionary <string, string> > GetProcessEnvironment(this DiagnosticsClientApiShim shim) { return(shim.GetProcessEnvironment(DefaultPositiveVerificationTimeout)); }