src\inc\llvm\ELF.h = src\inc\llvm\ELF.h
EndProjectSection
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotnetMonitor.UnitTests", "src\tests\dotnet-monitor\DotnetMonitor.UnitTests.csproj", "{6419BA04-6F1A-4D2F-8DE4-5C359E0364A3}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Diagnostics.Monitoring.UnitTests", "src\tests\Microsoft.Diagnostics.Monitoring\Microsoft.Diagnostics.Monitoring.UnitTests.csproj", "{6419BA04-6F1A-4D2F-8DE4-5C359E0364A3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventPipeTracee", "src\tests\EventPipeTracee\EventPipeTracee.csproj", "{870A7AD0-B808-491E-92F6-433BE990B374}"
EndProject
<ItemGroup>
<InternalsVisibleTo Include="dotnet-monitor" />
<!-- This is temporary until IEndpointInfoSourceInternal becomes public-->
- <InternalsVisibleTo Include="Microsoft.Diagnostics.Monitoring.RestServer" />
<InternalsVisibleTo Include="Microsoft.Diagnostics.Monitoring.EventPipe" />
- <InternalsVisibleTo Include="DotnetMonitor.UnitTests" />
<InternalsVisibleTo Include="Microsoft.Diagnostics.Monitoring.EventPipe.UnitTests" />
+ <InternalsVisibleTo Include="Microsoft.Diagnostics.Monitoring.RestServer" />
+ <InternalsVisibleTo Include="Microsoft.Diagnostics.Monitoring.UnitTests" />
</ItemGroup>
</Project>
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.Diagnostics.Monitoring;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Microsoft.Diagnostics.Monitoring.UnitTests
+{
+ public class CommandLineHelperTests
+ {
+ private readonly ITestOutputHelper _output;
+
+ public CommandLineHelperTests(ITestOutputHelper output)
+ {
+ _output = output;
+ }
+
+ [Theory]
+ [InlineData(true, null, null)]
+ [InlineData(true, "", "")]
+ [InlineData(true, @"C:\NoArgs\test.exe", @"C:\NoArgs\test.exe")]
+ [InlineData(true, @"C:\WithArgs\test.exe arg1 arg2", @"C:\WithArgs\test.exe")]
+ [InlineData(true, @"""C:\With Space No Args\test.exe""", @"C:\With Space No Args\test.exe")]
+ [InlineData(true, @"""C:\With Space With Args\test.exe"" arg1 arg2", @"C:\With Space With Args\test.exe")]
+ [InlineData(true, @"C:\With'Quotes'No'Args\test.exe", @"C:\With'Quotes'No'Args\test.exe")]
+ [InlineData(true, @"C:\With'Quotes'With'Args\test.exe arg1 arg2", @"C:\With'Quotes'With'Args\test.exe")]
+ [InlineData(false, null, null)]
+ [InlineData(false, "", "")]
+ [InlineData(false, "/home/noargs/test", "/home/noargs/test")]
+ [InlineData(false, "/home/withargs/test arg1 arg2", "/home/withargs/test")]
+ [InlineData(false, @"""/home/with space no args/test""", "/home/with space no args/test")]
+ [InlineData(false, @"""/home/with space with args/test"" arg1 arg2", "/home/with space with args/test")]
+ [InlineData(false, @"""/home/escaped\\backslashes\\no\\args/test""", @"/home/escaped\backslashes\no\args/test")]
+ [InlineData(false, @"""/home/escaped\\backslashes\\with\\args/test"" arg1 arg2", @"/home/escaped\backslashes\with\args/test")]
+ [InlineData(false, @"""/home/escaped\""quotes\""no\""args/test""", @"/home/escaped""quotes""no""args/test")]
+ [InlineData(false, @"""/home/escaped\""quotes\""with\""args/test"" arg1 arg2", @"/home/escaped""quotes""with""args/test")]
+ public void CommandLineValidPathTest(bool isWindows, string commandLine, string expectedProcessPath)
+ {
+ Assert.Equal(expectedProcessPath, CommandLineHelper.ExtractExecutablePath(commandLine, isWindows));
+ }
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Diagnostics.Monitoring;
+using Microsoft.Diagnostics.NETCore.Client;
+using Microsoft.Diagnostics.NETCore.Client.UnitTests;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Microsoft.Diagnostics.Monitoring.UnitTests
+{
+ public class EndpointInfoSourceTests
+ {
+ // Generous timeout to allow APIs to respond on slower or more constrained machines
+ private static readonly TimeSpan DefaultPositiveVerificationTimeout = TimeSpan.FromSeconds(30);
+ private static readonly TimeSpan DefaultNegativeVerificationTimeout = TimeSpan.FromSeconds(2);
+
+ private readonly ITestOutputHelper _outputHelper;
+
+ public EndpointInfoSourceTests(ITestOutputHelper outputHelper)
+ {
+ _outputHelper = outputHelper;
+ }
+
+ /// <summary>
+ /// Tests that other <see cref="ServerEndpointInfoSource"> methods throw if
+ /// <see cref="ServerEndpointInfoSource.Start"/> is not called.
+ /// </summary>
+ [Fact]
+ public async Task ServerSourceNoStartTest()
+ {
+ await using var source = CreateServerSource(out string transportName);
+ // Intentionally do not call Start
+
+ using CancellationTokenSource cancellation = new CancellationTokenSource(DefaultNegativeVerificationTimeout);
+
+ await Assert.ThrowsAsync<InvalidOperationException>(
+ () => source.GetEndpointInfoAsync(cancellation.Token));
+ }
+
+ /// <summary>
+ /// Tests that the server endpoint info source has not connections if no processes connect to it.
+ /// </summary>
+ [Fact]
+ public async Task ServerSourceNoConnectionsTest()
+ {
+ await using var source = CreateServerSource(out _);
+ source.Start();
+
+ var endpointInfos = await GetEndpointInfoAsync(source);
+ Assert.Empty(endpointInfos);
+ }
+
+ /// <summary>
+ /// Tests that server endpoint info source should throw ObjectDisposedException
+ /// from API surface after being disposed.
+ /// </summary>
+ [Fact]
+ public async Task ServerSourceThrowsWhenDisposedTest()
+ {
+ var source = CreateServerSource(out _);
+ source.Start();
+
+ await source.DisposeAsync();
+
+ // Validate source surface throws after disposal
+ Assert.Throws<ObjectDisposedException>(
+ () => source.Start());
+
+ Assert.Throws<ObjectDisposedException>(
+ () => source.Start(1));
+
+ using var cancellation = new CancellationTokenSource(DefaultNegativeVerificationTimeout);
+ await Assert.ThrowsAsync<ObjectDisposedException>(
+ () => source.GetEndpointInfoAsync(cancellation.Token));
+ }
+
+ /// <summary>
+ /// Tests that server endpoint info source should throw an exception from
+ /// <see cref="ServerEndpointInfoSource.Start"/> and
+ /// <see cref="ServerEndpointInfoSource.Start(int)"/> after listening was already started.
+ /// </summary>
+ [Fact]
+ public async Task ServerSourceThrowsWhenMultipleStartTest()
+ {
+ await using var source = CreateServerSource(out _);
+ source.Start();
+
+ Assert.Throws<InvalidOperationException>(
+ () => source.Start());
+
+ Assert.Throws<InvalidOperationException>(
+ () => source.Start(1));
+ }
+
+ /// <summary>
+ /// Tests that the server endpoint info source can properly enumerate endpoint infos when a single
+ /// target connects to it and "disconnects" from it.
+ /// </summary>
+ [Fact]
+ public async Task ServerSourceAddRemoveSingleConnectionTest()
+ {
+ await using var source = CreateServerSource(out string transportName);
+ source.Start();
+
+ var endpointInfos = await GetEndpointInfoAsync(source);
+ Assert.Empty(endpointInfos);
+
+ Task newEndpointInfoTask = source.WaitForNewEndpointInfoAsync(DefaultPositiveVerificationTimeout);
+
+ await using (var execution1 = StartTraceeProcess("LoggerRemoteTest", transportName))
+ {
+ await newEndpointInfoTask;
+
+ execution1.SendSignal();
+
+ endpointInfos = await GetEndpointInfoAsync(source);
+
+ var endpointInfo = Assert.Single(endpointInfos);
+ Assert.NotNull(endpointInfo.CommandLine);
+ Assert.NotNull(endpointInfo.OperatingSystem);
+ Assert.NotNull(endpointInfo.ProcessArchitecture);
+ VerifyConnection(execution1.TestRunner, endpointInfo);
+
+ _outputHelper.WriteLine("Stopping tracee.");
+ }
+
+ await Task.Delay(TimeSpan.FromSeconds(1));
+
+ endpointInfos = await GetEndpointInfoAsync(source);
+
+ Assert.Empty(endpointInfos);
+ }
+
+ private TestServerEndpointInfoSource CreateServerSource(out string transportName)
+ {
+ transportName = ReversedServerHelper.CreateServerTransportName();
+ _outputHelper.WriteLine("Starting server endpoint info source at '" + transportName + "'.");
+ return new TestServerEndpointInfoSource(transportName, _outputHelper);
+ }
+
+ private RemoteTestExecution StartTraceeProcess(string loggerCategory, string transportName = null)
+ {
+ _outputHelper.WriteLine("Starting tracee.");
+ string exePath = CommonHelper.GetTraceePathWithArgs("EventPipeTracee", targetFramework: "net5.0");
+ return RemoteTestExecution.StartProcess(exePath + " " + loggerCategory, _outputHelper, transportName);
+ }
+
+ private async Task<IEnumerable<IEndpointInfo>> GetEndpointInfoAsync(ServerEndpointInfoSource source)
+ {
+ _outputHelper.WriteLine("Getting endpoint infos.");
+ using CancellationTokenSource cancellationSource = new CancellationTokenSource(TimeSpan.FromSeconds(10));
+ return await source.GetEndpointInfoAsync(cancellationSource.Token);
+ }
+
+ /// <summary>
+ /// Verifies basic information on the connection and that it matches the target process from the runner.
+ /// </summary>
+ private static void VerifyConnection(TestRunner runner, IEndpointInfo endpointInfo)
+ {
+ Assert.NotNull(runner);
+ Assert.NotNull(endpointInfo);
+ Assert.Equal(runner.Pid, endpointInfo.ProcessId);
+ Assert.NotEqual(Guid.Empty, endpointInfo.RuntimeInstanceCookie);
+ Assert.NotNull(endpointInfo.Endpoint);
+ }
+
+ private sealed class TestServerEndpointInfoSource : ServerEndpointInfoSource
+ {
+ private readonly ITestOutputHelper _outputHelper;
+ private readonly List<TaskCompletionSource<EndpointInfo>> _addedEndpointInfoSources = new List<TaskCompletionSource<EndpointInfo>>();
+
+ public TestServerEndpointInfoSource(string transportPath, ITestOutputHelper outputHelper)
+ : base(transportPath)
+ {
+ _outputHelper = outputHelper;
+ }
+
+ public async Task<EndpointInfo> WaitForNewEndpointInfoAsync(TimeSpan timeout)
+ {
+ TaskCompletionSource<EndpointInfo> addedEndpointInfoSource = new TaskCompletionSource<EndpointInfo>(TaskCreationOptions.RunContinuationsAsynchronously);
+ using var timeoutCancellation = new CancellationTokenSource();
+ var token = timeoutCancellation.Token;
+ using var _ = token.Register(() => addedEndpointInfoSource.TrySetCanceled(token));
+
+ lock (_addedEndpointInfoSources)
+ {
+ _addedEndpointInfoSources.Add(addedEndpointInfoSource);
+ }
+
+ _outputHelper.WriteLine("Waiting for new endpoint info.");
+ timeoutCancellation.CancelAfter(timeout);
+ EndpointInfo endpointInfo = await addedEndpointInfoSource.Task;
+ _outputHelper.WriteLine("Notified of new endpoint info.");
+
+ return endpointInfo;
+ }
+
+ internal override void OnAddedEndpointInfo(EndpointInfo info)
+ {
+ _outputHelper.WriteLine($"Added endpoint info to collection: {info.DebuggerDisplay}");
+
+ lock (_addedEndpointInfoSources)
+ {
+ foreach (var source in _addedEndpointInfoSources)
+ {
+ source.TrySetResult(info);
+ }
+ _addedEndpointInfoSources.Clear();
+ }
+ }
+
+ internal override void OnRemovedEndpointInfo(EndpointInfo info)
+ {
+ _outputHelper.WriteLine($"Removed endpoint info from collection: {info.DebuggerDisplay}");
+ }
+ }
+ }
+}
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFrameworks>netcoreapp3.1;net5.0</TargetFrameworks>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="$(MSBuildThisFileDirectory)..\..\Microsoft.Diagnostics.Monitoring\Microsoft.Diagnostics.Monitoring.csproj" />
+ <ProjectReference Include="$(MSBuildThisFileDirectory)..\..\Microsoft.Diagnostics.Monitoring.EventPipe\Microsoft.Diagnostics.Monitoring.EventPipe.csproj" />
+ <ProjectReference Include="$(MSBuildThisFileDirectory)..\..\Microsoft.Diagnostics.NETCore.Client\Microsoft.Diagnostics.NETCore.Client.csproj" />
+ <ProjectReference Include="$(MSBuildThisFileDirectory)..\Microsoft.Diagnostics.NETCore.Client\Microsoft.Diagnostics.NETCore.Client.UnitTests.csproj" />
+ <ProjectReference Include="..\EventPipeTracee\EventPipeTracee.csproj" PrivateAssets="all" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="$(MicrosoftBclAsyncInterfacesVersion)" />
+ <PackageReference Include="xunit.abstractions" Version="$(XUnitAbstractionsVersion)" />
+ <PackageReference Include="System.Text.Json" Version="$(SystemTextJsonVersion)" />
+ </ItemGroup>
+
+</Project>
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.Diagnostics.Monitoring;
+using Microsoft.Diagnostics.Tracing.Parsers.Kernel;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Microsoft.Diagnostics.Monitoring.UnitTests
+{
+ public class PipelineTests
+ {
+ private readonly ITestOutputHelper _outputHelper;
+
+ public PipelineTests(ITestOutputHelper outputHelper)
+ {
+ _outputHelper = outputHelper;
+ }
+
+ [Fact]
+ public async Task TestStartStopCancelDispose()
+ {
+ var timePipeline = new DelayPipeline();
+ var cancellationTokenSource = new CancellationTokenSource();
+ var token = cancellationTokenSource.Token;
+
+ await Assert.ThrowsAsync<PipelineException>(() => timePipeline.StopAsync());
+
+ var startTask = timePipeline.RunAsync(token);
+ var secondStartCall = timePipeline.RunAsync(token);
+ Assert.Equal(startTask, secondStartCall);
+
+ var stopSource = new CancellationTokenSource();
+ var stopTask = timePipeline.StopAsync(stopSource.Token);
+ var secondStopCall = timePipeline.StopAsync(stopSource.Token);
+ Assert.Equal(stopTask, secondStopCall);
+
+ stopSource.Cancel();
+
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(() => stopTask);
+
+ cancellationTokenSource.Cancel();
+
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(() => startTask);
+
+ await timePipeline.DisposeAsync();
+
+ Assert.Equal(1, timePipeline.ExecutedCleanup);
+ }
+
+ [Fact]
+ public async Task TestStart()
+ {
+ var timePipeline = new DelayPipeline(TimeSpan.Zero);
+ await timePipeline.RunAsync(CancellationToken.None);
+
+ Assert.Equal(1, timePipeline.ExecutedCleanup);
+
+ await timePipeline.DisposeAsync();
+
+ Assert.Equal(1, timePipeline.ExecutedCleanup);
+ }
+
+ private sealed class DelayPipeline : Pipeline
+ {
+ public int ExecutedCleanup { get; private set; } = 0;
+ public TimeSpan Delay { get; }
+
+ public DelayPipeline() : this(Timeout.InfiniteTimeSpan)
+ {
+ }
+
+ public DelayPipeline(TimeSpan delay)
+ {
+ Delay = delay;
+ }
+
+ protected override Task OnRun(CancellationToken token)
+ {
+ return Task.Delay(Delay, token);
+ }
+
+ protected override Task OnStop(CancellationToken token)
+ {
+ return Task.Delay(Delay, token);
+ }
+
+ protected override Task OnCleanup()
+ {
+ ExecutedCleanup++;
+ return base.OnCleanup();
+ }
+ }
+ }
+}
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
<!--
DARCVersionFileName, GenerateDARCVersion, and InjectDARCVersion are used for injecting the value of MicrosoftNETCoreAppRuntimewinx64Version
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="$(MicrosoftDiagnosticsTracingTraceEventVersion)" />
</ItemGroup>
<ItemGroup>
- <InternalsVisibleTo Include="DotnetMonitor.UnitTests" />
<InternalsVisibleTo Include="DotnetStack.UnitTests" />
+ <InternalsVisibleTo Include="Microsoft.Diagnostics.Monitoring.UnitTests" />
</ItemGroup>
</Project>
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using Microsoft.Diagnostics.Monitoring;
-using Xunit;
-using Xunit.Abstractions;
-
-namespace DotnetMonitor.UnitTests
-{
- public class CommandLineHelperTests
- {
- private readonly ITestOutputHelper _output;
-
- public CommandLineHelperTests(ITestOutputHelper output)
- {
- _output = output;
- }
-
- [Theory]
- [InlineData(true, null, null)]
- [InlineData(true, "", "")]
- [InlineData(true, @"C:\NoArgs\test.exe", @"C:\NoArgs\test.exe")]
- [InlineData(true, @"C:\WithArgs\test.exe arg1 arg2", @"C:\WithArgs\test.exe")]
- [InlineData(true, @"""C:\With Space No Args\test.exe""", @"C:\With Space No Args\test.exe")]
- [InlineData(true, @"""C:\With Space With Args\test.exe"" arg1 arg2", @"C:\With Space With Args\test.exe")]
- [InlineData(true, @"C:\With'Quotes'No'Args\test.exe", @"C:\With'Quotes'No'Args\test.exe")]
- [InlineData(true, @"C:\With'Quotes'With'Args\test.exe arg1 arg2", @"C:\With'Quotes'With'Args\test.exe")]
- [InlineData(false, null, null)]
- [InlineData(false, "", "")]
- [InlineData(false, "/home/noargs/test", "/home/noargs/test")]
- [InlineData(false, "/home/withargs/test arg1 arg2", "/home/withargs/test")]
- [InlineData(false, @"""/home/with space no args/test""", "/home/with space no args/test")]
- [InlineData(false, @"""/home/with space with args/test"" arg1 arg2", "/home/with space with args/test")]
- [InlineData(false, @"""/home/escaped\\backslashes\\no\\args/test""", @"/home/escaped\backslashes\no\args/test")]
- [InlineData(false, @"""/home/escaped\\backslashes\\with\\args/test"" arg1 arg2", @"/home/escaped\backslashes\with\args/test")]
- [InlineData(false, @"""/home/escaped\""quotes\""no\""args/test""", @"/home/escaped""quotes""no""args/test")]
- [InlineData(false, @"""/home/escaped\""quotes\""with\""args/test"" arg1 arg2", @"/home/escaped""quotes""with""args/test")]
- public void CommandLineValidPathTest(bool isWindows, string commandLine, string expectedProcessPath)
- {
- Assert.Equal(expectedProcessPath, CommandLineHelper.ExtractExecutablePath(commandLine, isWindows));
- }
- }
-}
+++ /dev/null
-<Project Sdk="Microsoft.NET.Sdk">
-
- <PropertyGroup>
- <TargetFrameworks>netcoreapp3.1;net5.0</TargetFrameworks>
- </PropertyGroup>
-
- <ItemGroup>
- <ProjectReference Include="$(MSBuildThisFileDirectory)..\..\Microsoft.Diagnostics.Monitoring\Microsoft.Diagnostics.Monitoring.csproj" />
- <ProjectReference Include="$(MSBuildThisFileDirectory)..\..\Microsoft.Diagnostics.Monitoring.EventPipe\Microsoft.Diagnostics.Monitoring.EventPipe.csproj" />
- <ProjectReference Include="$(MSBuildThisFileDirectory)..\..\Microsoft.Diagnostics.NETCore.Client\Microsoft.Diagnostics.NETCore.Client.csproj" />
- <ProjectReference Include="$(MSBuildThisFileDirectory)..\Microsoft.Diagnostics.NETCore.Client\Microsoft.Diagnostics.NETCore.Client.UnitTests.csproj" />
- <ProjectReference Include="..\EventPipeTracee\EventPipeTracee.csproj" PrivateAssets="all" />
- </ItemGroup>
-
- <ItemGroup>
- <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="$(MicrosoftBclAsyncInterfacesVersion)" />
- <PackageReference Include="xunit.abstractions" Version="$(XUnitAbstractionsVersion)" />
- <PackageReference Include="System.Text.Json" Version="$(SystemTextJsonVersion)" />
- </ItemGroup>
-
-</Project>
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.Diagnostics.Monitoring;
-using Microsoft.Diagnostics.NETCore.Client;
-using Microsoft.Diagnostics.NETCore.Client.UnitTests;
-using Xunit;
-using Xunit.Abstractions;
-
-namespace DotnetMonitor.UnitTests
-{
- public class EndpointInfoSourceTests
- {
- // Generous timeout to allow APIs to respond on slower or more constrained machines
- private static readonly TimeSpan DefaultPositiveVerificationTimeout = TimeSpan.FromSeconds(30);
- private static readonly TimeSpan DefaultNegativeVerificationTimeout = TimeSpan.FromSeconds(2);
-
- private readonly ITestOutputHelper _outputHelper;
-
- public EndpointInfoSourceTests(ITestOutputHelper outputHelper)
- {
- _outputHelper = outputHelper;
- }
-
- /// <summary>
- /// Tests that other <see cref="ServerEndpointInfoSource"> methods throw if
- /// <see cref="ServerEndpointInfoSource.Start"/> is not called.
- /// </summary>
- [Fact]
- public async Task ServerSourceNoStartTest()
- {
- await using var source = CreateServerSource(out string transportName);
- // Intentionally do not call Start
-
- using CancellationTokenSource cancellation = new CancellationTokenSource(DefaultNegativeVerificationTimeout);
-
- await Assert.ThrowsAsync<InvalidOperationException>(
- () => source.GetEndpointInfoAsync(cancellation.Token));
- }
-
- /// <summary>
- /// Tests that the server endpoint info source has not connections if no processes connect to it.
- /// </summary>
- [Fact]
- public async Task ServerSourceNoConnectionsTest()
- {
- await using var source = CreateServerSource(out _);
- source.Start();
-
- var endpointInfos = await GetEndpointInfoAsync(source);
- Assert.Empty(endpointInfos);
- }
-
- /// <summary>
- /// Tests that server endpoint info source should throw ObjectDisposedException
- /// from API surface after being disposed.
- /// </summary>
- [Fact]
- public async Task ServerSourceThrowsWhenDisposedTest()
- {
- var source = CreateServerSource(out _);
- source.Start();
-
- await source.DisposeAsync();
-
- // Validate source surface throws after disposal
- Assert.Throws<ObjectDisposedException>(
- () => source.Start());
-
- Assert.Throws<ObjectDisposedException>(
- () => source.Start(1));
-
- using var cancellation = new CancellationTokenSource(DefaultNegativeVerificationTimeout);
- await Assert.ThrowsAsync<ObjectDisposedException>(
- () => source.GetEndpointInfoAsync(cancellation.Token));
- }
-
- /// <summary>
- /// Tests that server endpoint info source should throw an exception from
- /// <see cref="ServerEndpointInfoSource.Start"/> and
- /// <see cref="ServerEndpointInfoSource.Start(int)"/> after listening was already started.
- /// </summary>
- [Fact]
- public async Task ServerSourceThrowsWhenMultipleStartTest()
- {
- await using var source = CreateServerSource(out _);
- source.Start();
-
- Assert.Throws<InvalidOperationException>(
- () => source.Start());
-
- Assert.Throws<InvalidOperationException>(
- () => source.Start(1));
- }
-
- /// <summary>
- /// Tests that the server endpoint info source can properly enumerate endpoint infos when a single
- /// target connects to it and "disconnects" from it.
- /// </summary>
- [Fact]
- public async Task ServerSourceAddRemoveSingleConnectionTest()
- {
- await using var source = CreateServerSource(out string transportName);
- source.Start();
-
- var endpointInfos = await GetEndpointInfoAsync(source);
- Assert.Empty(endpointInfos);
-
- Task newEndpointInfoTask = source.WaitForNewEndpointInfoAsync(DefaultPositiveVerificationTimeout);
-
- await using (var execution1 = StartTraceeProcess("LoggerRemoteTest", transportName))
- {
- await newEndpointInfoTask;
-
- execution1.SendSignal();
-
- endpointInfos = await GetEndpointInfoAsync(source);
-
- var endpointInfo = Assert.Single(endpointInfos);
- Assert.NotNull(endpointInfo.CommandLine);
- Assert.NotNull(endpointInfo.OperatingSystem);
- Assert.NotNull(endpointInfo.ProcessArchitecture);
- VerifyConnection(execution1.TestRunner, endpointInfo);
-
- _outputHelper.WriteLine("Stopping tracee.");
- }
-
- await Task.Delay(TimeSpan.FromSeconds(1));
-
- endpointInfos = await GetEndpointInfoAsync(source);
-
- Assert.Empty(endpointInfos);
- }
-
- private TestServerEndpointInfoSource CreateServerSource(out string transportName)
- {
- transportName = ReversedServerHelper.CreateServerTransportName();
- _outputHelper.WriteLine("Starting server endpoint info source at '" + transportName + "'.");
- return new TestServerEndpointInfoSource(transportName, _outputHelper);
- }
-
- private RemoteTestExecution StartTraceeProcess(string loggerCategory, string transportName = null)
- {
- _outputHelper.WriteLine("Starting tracee.");
- string exePath = CommonHelper.GetTraceePathWithArgs("EventPipeTracee", targetFramework: "net5.0");
- return RemoteTestExecution.StartProcess(exePath + " " + loggerCategory, _outputHelper, transportName);
- }
-
- private async Task<IEnumerable<IEndpointInfo>> GetEndpointInfoAsync(ServerEndpointInfoSource source)
- {
- _outputHelper.WriteLine("Getting endpoint infos.");
- using CancellationTokenSource cancellationSource = new CancellationTokenSource(TimeSpan.FromSeconds(10));
- return await source.GetEndpointInfoAsync(cancellationSource.Token);
- }
-
- /// <summary>
- /// Verifies basic information on the connection and that it matches the target process from the runner.
- /// </summary>
- private static void VerifyConnection(TestRunner runner, IEndpointInfo endpointInfo)
- {
- Assert.NotNull(runner);
- Assert.NotNull(endpointInfo);
- Assert.Equal(runner.Pid, endpointInfo.ProcessId);
- Assert.NotEqual(Guid.Empty, endpointInfo.RuntimeInstanceCookie);
- Assert.NotNull(endpointInfo.Endpoint);
- }
-
- private sealed class TestServerEndpointInfoSource : ServerEndpointInfoSource
- {
- private readonly ITestOutputHelper _outputHelper;
- private readonly List<TaskCompletionSource<EndpointInfo>> _addedEndpointInfoSources = new List<TaskCompletionSource<EndpointInfo>>();
-
- public TestServerEndpointInfoSource(string transportPath, ITestOutputHelper outputHelper)
- : base(transportPath)
- {
- _outputHelper = outputHelper;
- }
-
- public async Task<EndpointInfo> WaitForNewEndpointInfoAsync(TimeSpan timeout)
- {
- TaskCompletionSource<EndpointInfo> addedEndpointInfoSource = new TaskCompletionSource<EndpointInfo>(TaskCreationOptions.RunContinuationsAsynchronously);
- using var timeoutCancellation = new CancellationTokenSource();
- var token = timeoutCancellation.Token;
- using var _ = token.Register(() => addedEndpointInfoSource.TrySetCanceled(token));
-
- lock (_addedEndpointInfoSources)
- {
- _addedEndpointInfoSources.Add(addedEndpointInfoSource);
- }
-
- _outputHelper.WriteLine("Waiting for new endpoint info.");
- timeoutCancellation.CancelAfter(timeout);
- EndpointInfo endpointInfo = await addedEndpointInfoSource.Task;
- _outputHelper.WriteLine("Notified of new endpoint info.");
-
- return endpointInfo;
- }
-
- internal override void OnAddedEndpointInfo(EndpointInfo info)
- {
- _outputHelper.WriteLine($"Added endpoint info to collection: {info.DebuggerDisplay}");
-
- lock (_addedEndpointInfoSources)
- {
- foreach (var source in _addedEndpointInfoSources)
- {
- source.TrySetResult(info);
- }
- _addedEndpointInfoSources.Clear();
- }
- }
-
- internal override void OnRemovedEndpointInfo(EndpointInfo info)
- {
- _outputHelper.WriteLine($"Removed endpoint info from collection: {info.DebuggerDisplay}");
- }
- }
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using Microsoft.Diagnostics.Monitoring;
-using Microsoft.Diagnostics.Tracing.Parsers.Kernel;
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using Xunit;
-using Xunit.Abstractions;
-
-namespace DotnetMonitor.UnitTests
-{
- public class PipelineTests
- {
- private readonly ITestOutputHelper _outputHelper;
-
- public PipelineTests(ITestOutputHelper outputHelper)
- {
- _outputHelper = outputHelper;
- }
-
- [Fact]
- public async Task TestStartStopCancelDispose()
- {
- var timePipeline = new DelayPipeline();
- var cancellationTokenSource = new CancellationTokenSource();
- var token = cancellationTokenSource.Token;
-
- await Assert.ThrowsAsync<PipelineException>(() => timePipeline.StopAsync());
-
- var startTask = timePipeline.RunAsync(token);
- var secondStartCall = timePipeline.RunAsync(token);
- Assert.Equal(startTask, secondStartCall);
-
- var stopSource = new CancellationTokenSource();
- var stopTask = timePipeline.StopAsync(stopSource.Token);
- var secondStopCall = timePipeline.StopAsync(stopSource.Token);
- Assert.Equal(stopTask, secondStopCall);
-
- stopSource.Cancel();
-
- await Assert.ThrowsAnyAsync<OperationCanceledException>(() => stopTask);
-
- cancellationTokenSource.Cancel();
-
- await Assert.ThrowsAnyAsync<OperationCanceledException>(() => startTask);
-
- await timePipeline.DisposeAsync();
-
- Assert.Equal(1, timePipeline.ExecutedCleanup);
- }
-
- [Fact]
- public async Task TestStart()
- {
- var timePipeline = new DelayPipeline(TimeSpan.Zero);
- await timePipeline.RunAsync(CancellationToken.None);
-
- Assert.Equal(1, timePipeline.ExecutedCleanup);
-
- await timePipeline.DisposeAsync();
-
- Assert.Equal(1, timePipeline.ExecutedCleanup);
- }
-
- private sealed class DelayPipeline : Pipeline
- {
- public int ExecutedCleanup { get; private set; } = 0;
- public TimeSpan Delay { get; }
-
- public DelayPipeline() : this(Timeout.InfiniteTimeSpan)
- {
- }
-
- public DelayPipeline(TimeSpan delay)
- {
- Delay = delay;
- }
-
- protected override Task OnRun(CancellationToken token)
- {
- return Task.Delay(Delay, token);
- }
-
- protected override Task OnStop(CancellationToken token)
- {
- return Task.Delay(Delay, token);
- }
-
- protected override Task OnCleanup()
- {
- ExecutedCleanup++;
- return base.OnCleanup();
- }
- }
- }
-}