public static async Task <bool> TEST_ServerWorksIfClientDoesntAccept() { string serverName = ReverseServer.MakeServerAddress(); Logger.logger.Log($"Server name is '{serverName}'"); var server = new ReverseServer(serverName); await RunSubprocess( serverName : serverName, duringExecution : async(int pid) => { var config = new SessionConfiguration( circularBufferSizeMB: 10, format: EventPipeSerializationFormat.NetTrace, providers: new List <Provider> { new Provider("Microsoft-DotNETCore-SampleProfiler") }); Logger.logger.Log("Starting EventPipeSession over standard connection"); using Stream stream = EventPipeClient.CollectTracing(pid, config, out var sessionId); Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId:x}"); using var source = new EventPipeEventSource(stream); Task readerTask = Task.Run(() => source.Process()); await Task.Delay(500); Logger.logger.Log("Stopping EventPipeSession over standard connection"); EventPipeClient.StopTracing(pid, sessionId); await readerTask; Logger.logger.Log("Stopped EventPipeSession over standard connection"); } ); server.Shutdown(); return(true); }
public static async Task <bool> TEST_CanConnectServerAndClientAtSameTime() { bool fSuccess = true; string serverName = ReverseServer.MakeServerAddress(); Logger.logger.Log($"Server name is '{serverName}'"); var server = new ReverseServer(serverName); Task <bool> subprocessTask = Utils.RunSubprocess( currentAssembly: Assembly.GetExecutingAssembly(), environment: new Dictionary <string, string> { { Utils.DiagnosticsMonitorAddressEnvKey, serverName }, { Utils.DiagnosticsMonitorPauseOnStartEnvKey, "0" } }, duringExecution: async(int pid) => { Task reverseTask = Task.Run(async() => { Logger.logger.Log($"Waiting for reverse connection"); Stream reverseStream = await server.AcceptAsync(); Logger.logger.Log("Got reverse connection"); IpcAdvertise advertise = IpcAdvertise.Parse(reverseStream); Logger.logger.Log(advertise.ToString()); }); Task regularTask = Task.Run(async() => { var config = new SessionConfiguration( circularBufferSizeMB: 1000, format: EventPipeSerializationFormat.NetTrace, providers: new List <Provider> { new Provider("Microsoft-DotNETCore-SampleProfiler") }); Logger.logger.Log("Starting EventPipeSession over standard connection"); using Stream stream = EventPipeClient.CollectTracing(pid, config, out var sessionId); Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId:x}"); using var source = new EventPipeEventSource(stream); Task readerTask = Task.Run(() => source.Process()); await Task.Delay(500); Logger.logger.Log("Stopping EventPipeSession over standard connection"); EventPipeClient.StopTracing(pid, sessionId); await readerTask; Logger.logger.Log("Stopped EventPipeSession over standard connection"); }); await Task.WhenAll(reverseTask, regularTask); } ); fSuccess &= await Utils.WaitTillTimeout(subprocessTask, TimeSpan.FromMinutes(1)); server.Shutdown(); return(fSuccess); }
public static async Task <bool> TEST_ServerIsResilientToNoBufferAgent() { bool fSuccess = true; // N.B. - this test is only testing behavior on Windows since Unix Domain Sockets get their buffer size from the // system configuration and isn't set here. Tests passing on Windows should indicate it would pass on Unix systems as well. string serverName = ReverseServer.MakeServerAddress(); Logger.logger.Log($"Server name is '{serverName}'"); var server = new ReverseServer(serverName, 0); Task <bool> subprocessTask = Utils.RunSubprocess( currentAssembly: Assembly.GetExecutingAssembly(), environment: new Dictionary <string, string> { { Utils.DiagnosticsMonitorAddressEnvKey, serverName }, { Utils.DiagnosticsMonitorPauseOnStartEnvKey, "0" } }, duringExecution: async(int pid) => { var config = new SessionConfiguration( circularBufferSizeMB: 10, format: EventPipeSerializationFormat.NetTrace, providers: new List <Provider> { new Provider("Microsoft-DotNETCore-SampleProfiler") }); Logger.logger.Log("Starting EventPipeSession over standard connection"); using Stream stream = EventPipeClient.CollectTracing(pid, config, out var sessionId); Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId:x}"); using var source = new EventPipeEventSource(stream); Task readerTask = Task.Run(() => source.Process()); await Task.Delay(500); Logger.logger.Log("Stopping EventPipeSession over standard connection"); EventPipeClient.StopTracing(pid, sessionId); await readerTask; Logger.logger.Log("Stopped EventPipeSession over standard connection"); } ); fSuccess &= await Utils.WaitTillTimeout(subprocessTask, TimeSpan.FromMinutes(1)); server.Shutdown(); return(fSuccess); }
public static async Task <bool> TEST_ServerWorksIfClientDoesntAccept() { bool fSuccess = true; string serverName = ReverseServer.MakeServerAddress(); Logger.logger.Log($"Server name is '{serverName}'"); var server = new ReverseServer(serverName); Task <bool> subprocessTask = Utils.RunSubprocess( currentAssembly: Assembly.GetExecutingAssembly(), environment: new Dictionary <string, string> { { Utils.DiagnosticsMonitorAddressEnvKey, serverName }, { Utils.DiagnosticsMonitorPauseOnStartEnvKey, "0" } }, duringExecution: async(int pid) => { var config = new SessionConfiguration( circularBufferSizeMB: 10, format: EventPipeSerializationFormat.NetTrace, providers: new List <Provider> { new Provider("Microsoft-DotNETCore-SampleProfiler") }); Logger.logger.Log("Starting EventPipeSession over standard connection"); using Stream stream = EventPipeClient.CollectTracing(pid, config, out var sessionId); Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId:x}"); using var source = new EventPipeEventSource(stream); Task readerTask = Task.Run(() => source.Process()); await Task.Delay(500); Logger.logger.Log("Stopping EventPipeSession over standard connection"); EventPipeClient.StopTracing(pid, sessionId); await readerTask; Logger.logger.Log("Stopped EventPipeSession over standard connection"); } ); fSuccess &= await subprocessTask; server.Shutdown(); return(true); }
public static async Task <bool> TEST_ServerIsResilientToNoBufferAgent() { // N.B. - this test is only testing behavior on Windows since Unix Domain Sockets get their buffer size from the // system configuration and isn't set here. Tests passing on Windows should indicate it would pass on Unix systems as well. string serverName = ReverseServer.MakeServerAddress(); Logger.logger.Log($"Server name is '{serverName}'"); var server = new ReverseServer(serverName, 0); await RunSubprocess( serverName : serverName, duringExecution : async(int pid) => { var config = new SessionConfiguration( circularBufferSizeMB: 10, format: EventPipeSerializationFormat.NetTrace, providers: new List <Provider> { new Provider("Microsoft-DotNETCore-SampleProfiler") }); Logger.logger.Log("Starting EventPipeSession over standard connection"); using Stream stream = EventPipeClient.CollectTracing(pid, config, out var sessionId); Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId:x}"); using var source = new EventPipeEventSource(stream); Task readerTask = Task.Run(() => source.Process()); await Task.Delay(500); Logger.logger.Log("Stopping EventPipeSession over standard connection"); EventPipeClient.StopTracing(pid, sessionId); await readerTask; Logger.logger.Log("Stopped EventPipeSession over standard connection"); } ); server.Shutdown(); return(true); }
public static async Task <bool> TEST_MultipleConnectPortsSuspend() { bool fSuccess = true; var serverAndNames = new List <(ReverseServer, string)>(); string dotnetDiagnosticPorts = ""; for (int i = 0; i < s_NumberOfPorts; i++) { string serverName = ReverseServer.MakeServerAddress(); var server = new ReverseServer(serverName); Logger.logger.Log($"Server {i} address is '{serverName}'"); serverAndNames.Add((server, serverName)); dotnetDiagnosticPorts += $"{serverName};"; } Logger.logger.Log($"export DOTNET_DiagnosticPorts={dotnetDiagnosticPorts}"); var advertisements = new List <IpcAdvertise>(); Object sync = new Object(); int subprocessId = -1; Task <bool> subprocessTask = Utils.RunSubprocess( currentAssembly: Assembly.GetExecutingAssembly(), environment: new Dictionary <string, string> { { Utils.DiagnosticPortsEnvKey, dotnetDiagnosticPorts } }, duringExecution: async(int pid) => { subprocessId = pid; // Create an eventpipe session that will tell us when // the EEStartupStarted event happens. This will tell us // the the runtime has been resumed. This should only happen // AFTER all suspend ports have sent the resume command. var config = new SessionConfiguration( circularBufferSizeMB: 1000, format: EventPipeSerializationFormat.NetTrace, providers: new List <Provider> { new Provider("Microsoft-Windows-DotNETRuntimePrivate", 0x80000000, EventLevel.Verbose), // workaround for https://github.com/dotnet/runtime/issues/44072 which happens because the // above provider only sends 2 events and that can cause EventPipeEventSource (from TraceEvent) // to not dispatch the events if the EventBlock is a size not divisible by 8 (the reading alignment in TraceEvent). // Adding this provider keeps data flowing over the pipe so the reader doesn't get stuck waiting for data // that won't come otherwise. new Provider("Microsoft-DotNETCore-SampleProfiler") }); Logger.logger.Log("Starting EventPipeSession over standard connection"); using Stream eventStream = EventPipeClient.CollectTracing(pid, config, out var sessionId); Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId:x}"); var mre = new ManualResetEvent(false); Task readerTask = Task.Run(async() => { Logger.logger.Log($"Creating EventPipeEventSource"); using var source = new EventPipeEventSource(eventStream); var parser = new ClrPrivateTraceEventParser(source); parser.StartupEEStartupStart += (eventData) => mre.Set(); Logger.logger.Log($"Created EventPipeEventSource"); Logger.logger.Log($"Starting processing"); await Task.Run(() => source.Process()); Logger.logger.Log($"Finished processing"); }); for (int i = 0; i < s_NumberOfPorts; i++) { fSuccess &= !mre.WaitOne(0); Logger.logger.Log($"Runtime HAS NOT resumed (expects: true): {fSuccess}"); var(server, _) = serverAndNames[i]; int serverIndex = i; Stream stream = await server.AcceptAsync(); IpcAdvertise advertise = IpcAdvertise.Parse(stream); lock (sync) advertisements.Add(advertise); Logger.logger.Log($"Server {serverIndex} got advertise {advertise.ToString()}"); // send resume command on this connection var message = new IpcMessage(0x04, 0x01); Logger.logger.Log($"Port {serverIndex} sent: {message.ToString()}"); IpcMessage response = IpcClient.SendMessage(stream, message); Logger.logger.Log($"Port {serverIndex} received: {response.ToString()}"); } Logger.logger.Log($"Waiting on EEStartupStarted event"); mre.WaitOne(); Logger.logger.Log($"Saw EEStartupStarted Event"); Logger.logger.Log($"Stopping EventPipeSession"); EventPipeClient.StopTracing(pid, sessionId); await readerTask; Logger.logger.Log($"Stopped EventPipeSession"); // runtime should have resumed now fSuccess &= mre.WaitOne(0); Logger.logger.Log($"Runtime HAS resumed (expects: true): {fSuccess}"); } ); fSuccess &= await subprocessTask; foreach (var(server, _) in serverAndNames) { server.Shutdown(); } if (advertisements.Count() > 0) { Guid referenceCookie = advertisements[0].RuntimeInstanceCookie; foreach (var adv in advertisements) { fSuccess &= (int)adv.ProcessId == subprocessId; fSuccess &= adv.RuntimeInstanceCookie.Equals(referenceCookie); } } else { fSuccess &= false; } return(fSuccess); }
public static async Task <bool> TEST_ConfigValidation() { // load the env var with good and bad configs. Operation of good configs shouldn't be impeded by bad ones. // This test assumes all good configs have a server at the other end of the specified path. // Note that while a bad config might not crash the application, it may still degrade the process, e.g., // a bad configuration that specifies at least a path, will most likely still be built and consume resources polling // for a server that won't exist. bool fSuccess = true; var serverAndNames = new List <(ReverseServer, string)>(); string dotnetDiagnosticPorts = ""; // TODO: Make sure these don't hang the test when the default is suspend dotnetDiagnosticPorts += ";;;;;;"; // empty configs shouldn't cause a crash dotnetDiagnosticPorts += " ; ; ; ; ; ; ; ; ;"; // whitespace only configs shouldn't cause a crash dotnetDiagnosticPorts += " , , , , , ,;,,,,,;;"; // whitespace configs and empty tags with no path shouldn't cause a crash dotnetDiagnosticPorts += "connect,connect,connect,nosuspend,nosuspend,nosuspend,,,;"; // path that is the same as a tag name and duplicate tags shouldn't cause a crash dotnetDiagnosticPorts += "SomeRandomPath,nosuspend,suspend,suspend,suspend,suspend;"; // only the first tag from a pair is respected (this should result in a nosuspend port) dotnetDiagnosticPorts += "%%bad_Path^* fasdf----##2~~,bad tag$$@#@%_)*)@!#(&%.>, , , , ,nosuspend,:::;"; // invalid path chars and tag chars won't cause a crash for (int i = 0; i < s_NumberOfPorts; i++) { string serverName = ReverseServer.MakeServerAddress(); var server = new ReverseServer(serverName); Logger.logger.Log($"Server {i} address is '{serverName}'"); serverAndNames.Add((server, serverName)); dotnetDiagnosticPorts += $"{serverName},nosuspend;"; dotnetDiagnosticPorts += $"{serverName},nosuspend;"; // duplicating port configs shouldn't cause issues } Logger.logger.Log($"export DOTNET_DiagnosticPorts={dotnetDiagnosticPorts}"); var advertisements = new List <IpcAdvertise>(); Object sync = new Object(); int subprocessId = -1; Task <bool> subprocessTask = Utils.RunSubprocess( currentAssembly: Assembly.GetExecutingAssembly(), environment: new Dictionary <string, string> { { Utils.DiagnosticPortsEnvKey, dotnetDiagnosticPorts } }, duringExecution: async(int pid) => { subprocessId = pid; var tasks = new List <Task>(); for (int i = 0; i < s_NumberOfPorts; i++) { var(server, _) = serverAndNames[i]; int serverIndex = i; tasks.Add(Task.Run(async() => { Stream stream = await server.AcceptAsync(); IpcAdvertise advertise = IpcAdvertise.Parse(stream); lock (sync) advertisements.Add(advertise); Logger.logger.Log($"Server {serverIndex} got advertise {advertise.ToString()}"); })); } await Task.WhenAll(tasks); } ); fSuccess &= await subprocessTask; foreach (var(server, _) in serverAndNames) { server.Shutdown(); } Guid referenceCookie = advertisements[0].RuntimeInstanceCookie; foreach (var adv in advertisements) { fSuccess &= (int)adv.ProcessId == subprocessId; fSuccess &= adv.RuntimeInstanceCookie.Equals(referenceCookie); } return(fSuccess); }
public static async Task <bool> TEST_MultipleConnectPortsNoSuspend() { bool fSuccess = true; var serverAndNames = new List <(ReverseServer, string)>(); string dotnetDiagnosticPorts = ""; for (int i = 0; i < s_NumberOfPorts; i++) { string serverName = ReverseServer.MakeServerAddress(); var server = new ReverseServer(serverName); Logger.logger.Log($"Server {i} address is '{serverName}'"); serverAndNames.Add((server, serverName)); dotnetDiagnosticPorts += $"{serverName},nosuspend;"; } Logger.logger.Log($"export DOTNET_DiagnosticPorts={dotnetDiagnosticPorts}"); var advertisements = new List <IpcAdvertise>(); Object sync = new Object(); int subprocessId = -1; Task <bool> subprocessTask = Utils.RunSubprocess( currentAssembly: Assembly.GetExecutingAssembly(), environment: new Dictionary <string, string> { { Utils.DiagnosticPortsEnvKey, dotnetDiagnosticPorts } }, duringExecution: async(int pid) => { subprocessId = pid; var tasks = new List <Task>(); for (int i = 0; i < s_NumberOfPorts; i++) { var(server, _) = serverAndNames[i]; int serverIndex = i; tasks.Add(Task.Run(async() => { Stream stream = await server.AcceptAsync(); IpcAdvertise advertise = IpcAdvertise.Parse(stream); lock (sync) advertisements.Add(advertise); Logger.logger.Log($"Server {serverIndex} got advertise {advertise.ToString()}"); })); } await Task.WhenAll(tasks); } ); fSuccess &= await subprocessTask; foreach (var(server, _) in serverAndNames) { server.Shutdown(); } Guid referenceCookie = advertisements[0].RuntimeInstanceCookie; foreach (var adv in advertisements) { fSuccess &= (int)adv.ProcessId == subprocessId; fSuccess &= adv.RuntimeInstanceCookie.Equals(referenceCookie); } return(fSuccess); }