diff --git a/NuGet.config b/NuGet.config index fd1f2a9ce2..de789f31f8 100644 --- a/NuGet.config +++ b/NuGet.config @@ -7,7 +7,6 @@ - diff --git a/diagnostics.sln b/diagnostics.sln index 5f940760e0..1a0860f67d 100644 --- a/diagnostics.sln +++ b/diagnostics.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29019.234 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32519.111 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Diagnostics.TestHelpers", "src\Microsoft.Diagnostics.TestHelpers\Microsoft.Diagnostics.TestHelpers.csproj", "{730C1201-1848-4F1E-8C1F-6316FB886C35}" EndProject @@ -41,9 +41,6 @@ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SOS.Symbol.Package", "src\SOS\SOS.Package\SOS.Symbol.Package.csproj", "{410394E0-7F4F-42D5-B5FA-30956F44ACBC}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{03479E19-3F18-49A6-910A-F5041E27E7C0}" - ProjectSection(SolutionItems) = preProject - src\tests\eventpipe\EventPipe.UnitTests.csproj = src\tests\eventpipe\EventPipe.UnitTests.csproj - EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotnetTrace.UnitTests", "src\tests\dotnet-trace\DotnetTrace.UnitTests.csproj", "{AEDCCF5B-5AD0-4D64-BF73-5CF468E07D22}" EndProject @@ -173,8 +170,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "inc", "inc", "{41BDFD6D-D16 src\shared\inc\sstring.h = src\shared\inc\sstring.h src\shared\inc\sstring.inl = src\shared\inc\sstring.inl src\shared\inc\stacktrace.h = src\shared\inc\stacktrace.h - src\shared\inc\static_assert.h = src\shared\inc\static_assert.h src\shared\inc\staticcontract.h = src\shared\inc\staticcontract.h + src\shared\inc\static_assert.h = src\shared\inc\static_assert.h src\shared\inc\stdmacros.h = src\shared\inc\stdmacros.h src\shared\inc\stresslog.h = src\shared\inc\stresslog.h src\shared\inc\switches.h = src\shared\inc\switches.h @@ -265,6 +262,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "minipal", "minipal", "{795B EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DbgShim.UnitTests", "src\tests\DbgShim.UnitTests\DbgShim.UnitTests.csproj", "{DD60B7C4-BECC-4C7D-A53B-FCDD4C92B728}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CommonTestRunner", "src\tests\CommonTestRunner\CommonTestRunner.csproj", "{DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotnetStack.UnitTests", "src\tests\dotnet-stack\DotnetStack.UnitTests.csproj", "{E8F133F8-4D20-475D-9D16-2BA236DAB65F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Checked|Any CPU = Checked|Any CPU @@ -1786,6 +1787,84 @@ Global {DD60B7C4-BECC-4C7D-A53B-FCDD4C92B728}.RelWithDebInfo|x64.Build.0 = Release|Any CPU {DD60B7C4-BECC-4C7D-A53B-FCDD4C92B728}.RelWithDebInfo|x86.ActiveCfg = Release|Any CPU {DD60B7C4-BECC-4C7D-A53B-FCDD4C92B728}.RelWithDebInfo|x86.Build.0 = Release|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Checked|Any CPU.Build.0 = Debug|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Checked|ARM.ActiveCfg = Debug|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Checked|ARM.Build.0 = Debug|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Checked|ARM64.ActiveCfg = Debug|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Checked|ARM64.Build.0 = Debug|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Checked|x64.ActiveCfg = Debug|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Checked|x64.Build.0 = Debug|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Checked|x86.ActiveCfg = Debug|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Checked|x86.Build.0 = Debug|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Debug|ARM.ActiveCfg = Debug|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Debug|ARM.Build.0 = Debug|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Debug|ARM64.Build.0 = Debug|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Debug|x64.ActiveCfg = Debug|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Debug|x64.Build.0 = Debug|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Debug|x86.ActiveCfg = Debug|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Debug|x86.Build.0 = Debug|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Release|Any CPU.Build.0 = Release|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Release|ARM.ActiveCfg = Release|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Release|ARM.Build.0 = Release|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Release|ARM64.ActiveCfg = Release|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Release|ARM64.Build.0 = Release|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Release|x64.ActiveCfg = Release|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Release|x64.Build.0 = Release|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Release|x86.ActiveCfg = Release|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.Release|x86.Build.0 = Release|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.RelWithDebInfo|ARM.ActiveCfg = Release|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.RelWithDebInfo|ARM.Build.0 = Release|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.RelWithDebInfo|ARM64.ActiveCfg = Release|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.RelWithDebInfo|ARM64.Build.0 = Release|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.RelWithDebInfo|x64.Build.0 = Release|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.RelWithDebInfo|x86.ActiveCfg = Release|Any CPU + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F}.RelWithDebInfo|x86.Build.0 = Release|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Checked|Any CPU.Build.0 = Debug|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Checked|ARM.ActiveCfg = Debug|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Checked|ARM.Build.0 = Debug|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Checked|ARM64.ActiveCfg = Debug|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Checked|ARM64.Build.0 = Debug|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Checked|x64.ActiveCfg = Debug|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Checked|x64.Build.0 = Debug|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Checked|x86.ActiveCfg = Debug|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Checked|x86.Build.0 = Debug|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Debug|ARM.ActiveCfg = Debug|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Debug|ARM.Build.0 = Debug|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Debug|ARM64.Build.0 = Debug|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Debug|x64.ActiveCfg = Debug|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Debug|x64.Build.0 = Debug|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Debug|x86.ActiveCfg = Debug|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Debug|x86.Build.0 = Debug|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Release|ARM.ActiveCfg = Release|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Release|ARM.Build.0 = Release|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Release|ARM64.ActiveCfg = Release|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Release|ARM64.Build.0 = Release|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Release|x64.ActiveCfg = Release|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Release|x64.Build.0 = Release|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Release|x86.ActiveCfg = Release|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.Release|x86.Build.0 = Release|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.RelWithDebInfo|ARM.ActiveCfg = Release|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.RelWithDebInfo|ARM.Build.0 = Release|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.RelWithDebInfo|ARM64.ActiveCfg = Release|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.RelWithDebInfo|ARM64.Build.0 = Release|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.RelWithDebInfo|x64.Build.0 = Release|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.RelWithDebInfo|x86.ActiveCfg = Release|Any CPU + {E8F133F8-4D20-475D-9D16-2BA236DAB65F}.RelWithDebInfo|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1842,6 +1921,8 @@ Global {8C35FEF8-1101-38F6-ACD0-462A1EA53A7D} = {7852EDE4-93DF-4DB1-8A86-C521703811AF} {795B7A50-1B1F-406E-94E0-F9B35104EF22} = {7852EDE4-93DF-4DB1-8A86-C521703811AF} {DD60B7C4-BECC-4C7D-A53B-FCDD4C92B728} = {03479E19-3F18-49A6-910A-F5041E27E7C0} + {DFF48CB6-4504-41C6-A8F1-F4A3D316D49F} = {03479E19-3F18-49A6-910A-F5041E27E7C0} + {E8F133F8-4D20-475D-9D16-2BA236DAB65F} = {03479E19-3F18-49A6-910A-F5041E27E7C0} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {46465737-C938-44FC-BE1A-4CE139EBB5E0} diff --git a/eng/InstallRuntimes.proj b/eng/InstallRuntimes.proj index c11cd5f6ac..eac7bdc378 100644 --- a/eng/InstallRuntimes.proj +++ b/eng/InstallRuntimes.proj @@ -15,16 +15,17 @@ $(MicrosoftDotnetSdkInternalVersion) - .NET SDK to use for testing - $(VSRedistCommonNetCoreSharedFrameworkx6460Version) - latest dotnet runtime package version (the version to install) - $(MicrosoftNETCoreAppRuntimewinx64Version) - latest dotnet runtime stable version (the version that actually is installed) + $(VSRedistCommonNetCoreSharedFrameworkx6470Version) - latest dotnet runtime package version (the version to install) + $(MicrosoftNETCoreAppRuntimewinx64Version) - latest dotnet runtime stable version (the version that actually is installed) - $(MicrosoftAspNetCoreAppRefInternalVersion) - latest dotnet aspnetcore package version (the version to install) - $(MicrosoftAspNetCoreAppRefVersion) - latest dotnet aspnetcore stable version (the version that actually is installed) + $(MicrosoftAspNetCoreAppRefInternalVersion) - latest dotnet aspnetcore package version (the version to install) + $(MicrosoftAspNetCoreAppRefVersion) - latest dotnet aspnetcore stable version (the version that actually is installed) - $(MicrosoftNETCoreApp50Version) $(MicrosoftAspNetCoreApp50Version) - 5.0 version - $(MicrosoftNETCoreApp31Version) $(MicrosoftAspNetCoreApp31Version) - 3.1 version + $(MicrosoftNETCoreApp60Version) $(MicrosoftAspNetCoreApp60Version) - 6.0 version + $(MicrosoftNETCoreApp31Version) $(MicrosoftAspNetCoreApp31Version) - 3.1 version - $(SingleFileRuntimeVersion) - The version of the runtime used to build single-file apps + $(SingleFileRuntimeLatestVersion) - The latest version of the runtime used to build single-file apps + $(SingleFileRuntime60Version) - The 6.0.x version of the runtime used to build single-file apps From Arcade: @@ -63,6 +64,11 @@ regedit.exe + + true + false + + @@ -78,14 +84,14 @@ - - - + + + - + @@ -147,11 +153,11 @@ Outputs="$(TestConfigFileName)"> - $(MicrosoftNETCoreApp31Version) - $(MicrosoftAspNetCoreApp31Version) + $(MicrosoftNETCoreApp31Version) + $(MicrosoftAspNetCoreApp31Version) - $(MicrosoftNETCoreApp50Version) - $(MicrosoftAspNetCoreApp50Version) + $(MicrosoftNETCoreApp60Version) + $(MicrosoftAspNetCoreApp60Version) @@ -170,13 +176,14 @@ $(RuntimeVersion31) $(AspNetCoreVersion31) - $(RuntimeVersion50) - $(AspNetCoreVersion50) + $(RuntimeVersion60) + $(AspNetCoreVersion60) $(RuntimeVersionLatest) $(AspNetCoreVersionLatest) - $(SingleFileRuntimeVersion) + $(SingleFileRuntimeLatestVersion) + $(SingleFileRuntime60Version) ]]> diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index b85fc624a4..244495331c 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,7 +14,7 @@ https://github.com/dotnet/source-build-reference-packages - 993b067a1849e4884360b4548cbf74f0bfaa2f35 + 3dbb19f76474f2f22749b2e64d34c15178381ffb @@ -28,25 +28,25 @@ https://github.com/dotnet/arcade ccfe6da198c5f05534863bbb1bff66e830e0c6ab - + https://github.com/dotnet/installer - d62c7a24e4421ec3d70783fad181f50fde2e3901 + 51211d8d2eb12dfbee4d88d24eff9af26d6b7262 - + https://github.com/dotnet/aspnetcore - 511eaa8ee5923bf6e33fe86ae424bc79e4723003 + 154d0530fb24e142c22b5b737e881f1b7c0c65d3 - + https://github.com/dotnet/aspnetcore 511eaa8ee5923bf6e33fe86ae424bc79e4723003 - + https://github.com/dotnet/runtime - a21b9a2dd4c31cf5bd37626562b7612faf21cee6 + f21ace52e357bbf0019da5c9e42d66705a087235 - + https://github.com/dotnet/runtime - a21b9a2dd4c31cf5bd37626562b7612faf21cee6 + f21ace52e357bbf0019da5c9e42d66705a087235 diff --git a/eng/Versions.props b/eng/Versions.props index c1b8d7af23..72cc436113 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -15,23 +15,26 @@ true - - 6.0.5 1.0.332901 - - 3.1.18 - $(MicrosoftNETCoreApp31Version) - 5.0.9 - $(MicrosoftNETCoreApp50Version) - 6.0.5-servicing.22213.11 - 6.0.5 + 7.0.0-preview.6.22329.5 + 7.0.0-preview.6.22329.5 - 6.0.7-servicing.22313.13 - 6.0.7 + 7.0.0-preview.7.22330.6 + 7.0.0-preview.7.22330.6 - 6.0.107-servicing.22310.12 + 7.0.100-preview.7.22351.2 + + + + 3.1.25 + $(MicrosoftNETCoreApp31Version) + 6.0.6 + $(MicrosoftNETCoreApp60Version) + + 6.0.6 + 7.0.0-preview.6.22329.5 diff --git a/global.json b/global.json index 4f9b7f2039..ef7df67613 100644 --- a/global.json +++ b/global.json @@ -1,16 +1,20 @@ { "tools": { - "dotnet": "7.0.100-preview.2.22153.17", + "dotnet": "7.0.100-preview.3.22179.4", "runtimes": { "dotnet/x64": [ "$(MicrosoftNETCoreApp31Version)", - "$(MicrosoftNETCoreApp50Version)", - "$(VSRedistCommonNetCoreSharedFrameworkx6460Version)" + "$(MicrosoftNETCoreApp60Version)", + "$(VSRedistCommonNetCoreSharedFrameworkx6470Version)" ], "dotnet/x86": [ "$(MicrosoftNETCoreApp31Version)", - "$(MicrosoftNETCoreApp50Version)", - "$(VSRedistCommonNetCoreSharedFrameworkx6460Version)" + "$(MicrosoftNETCoreApp60Version)", + "$(VSRedistCommonNetCoreSharedFrameworkx6470Version)" + ], + "dotnet/arm64": [ + "$(MicrosoftNETCoreApp60Version)", + "$(VSRedistCommonNetCoreSharedFrameworkx6470Version)" ] } }, diff --git a/src/Microsoft.Diagnostics.DebugServices.Implementation/TargetFromDataReader.cs b/src/Microsoft.Diagnostics.DebugServices.Implementation/TargetFromDataReader.cs index ee499a3022..07d901bb04 100644 --- a/src/Microsoft.Diagnostics.DebugServices.Implementation/TargetFromDataReader.cs +++ b/src/Microsoft.Diagnostics.DebugServices.Implementation/TargetFromDataReader.cs @@ -49,8 +49,10 @@ public TargetFromDataReader(IDataReader dataReader, OSPlatform targetOS, IHost h { memoryService = new ImageMappingMemoryService(this, memoryService); // Any dump created for a MacOS target does not have managed assemblies in the module service so - // we need to use the metadata mapping memory service to make sure the metadata is available. - if (targetOS == OSPlatform.OSX) + // we need to use the metadata mapping memory service to make sure the metadata is available and + // 7.0 Linux builds have an extra System.Private.CoreLib module mapping that causes the image + // mapper not to be able to map in the metadata. + if (targetOS == OSPlatform.OSX || targetOS == OSPlatform.Linux) { memoryService = new MetadataMappingMemoryService(this, memoryService); } diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/Host/ModulesCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/Host/ModulesCommand.cs index 9a450ea1ad..74fd7a9cab 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/Host/ModulesCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/Host/ModulesCommand.cs @@ -28,51 +28,73 @@ public class ModulesCommand : CommandBase [Option(Name = "--name", Aliases = new string[] { "-n" }, Help = "RegEx filter on module name (path not included).")] public string ModuleName { get; set; } + [Option(Name = "--address", Aliases = new string[] { "-a" }, Help = "Lookup address in module list.")] + public ulong? Address { get; set; } + public IModuleService ModuleService { get; set; } public override void Invoke() { - Regex regex = ModuleName is not null ? new Regex(ModuleName, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant) : null; - ulong totalSize = 0; - - foreach (IModule module in ModuleService.EnumerateModules().OrderBy((m) => m.ModuleIndex)) + if (Address.HasValue) { - totalSize += module.ImageSize; - if (regex is null || !string.IsNullOrEmpty(module.FileName) && regex.IsMatch(Path.GetFileName(module.FileName))) + IModule module = ModuleService.GetModuleFromAddress(Address.Value); + if (module != null) { - if (Verbose) - { - WriteLine("{0} {1}", module.ModuleIndex, module.FileName); - WriteLine(" Address: {0:X16}", module.ImageBase); - WriteLine(" ImageSize: {0:X8}", module.ImageSize); - WriteLine(" IsPEImage: {0}", module.IsPEImage); - WriteLine(" IsManaged: {0}", module.IsManaged); - WriteLine(" IsFileLayout: {0}", module.IsFileLayout?.ToString() ?? ""); - WriteLine(" IndexFileSize: {0}", module.IndexFileSize?.ToString("X8") ?? ""); - WriteLine(" IndexTimeStamp: {0}", module.IndexTimeStamp?.ToString("X8") ?? ""); - WriteLine(" Version: {0}", module.GetVersionData()?.ToString() ?? ""); - string versionString = module.GetVersionString(); - if (!string.IsNullOrEmpty(versionString)) - { - WriteLine(" {0}", versionString); - } - foreach (PdbFileInfo pdbFileInfo in module.GetPdbFileInfos()) - { - WriteLine(" PdbInfo: {0}", pdbFileInfo); - } - WriteLine(" BuildId: {0}", !module.BuildId.IsDefaultOrEmpty ? string.Concat(module.BuildId.Select((b) => b.ToString("x2"))) : ""); - } - else - { - WriteLine("{0:X16} {1:X8} {2}", module.ImageBase, module.ImageSize, module.FileName); - } - if (Segment) + DisplayModule(module); + } + else + { + WriteLineError($"Address 0x{Address:X16} not found"); + } + } + else + { + Regex regex = ModuleName is not null ? new Regex(ModuleName, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant) : null; + ulong totalSize = 0; + foreach (IModule module in ModuleService.EnumerateModules().OrderBy((m) => m.ModuleIndex)) + { + totalSize += module.ImageSize; + if (regex is null || !string.IsNullOrEmpty(module.FileName) && regex.IsMatch(Path.GetFileName(module.FileName))) { - DisplaySegments(module); + DisplayModule(module); } } + WriteLine("Total image size: {0}", totalSize); + } + } + + void DisplayModule(IModule module) + { + if (Verbose) + { + WriteLine("{0} {1}", module.ModuleIndex, module.FileName); + WriteLine(" Address: {0:X16}", module.ImageBase); + WriteLine(" ImageSize: {0:X8}", module.ImageSize); + WriteLine(" IsPEImage: {0}", module.IsPEImage); + WriteLine(" IsManaged: {0}", module.IsManaged); + WriteLine(" IsFileLayout: {0}", module.IsFileLayout?.ToString() ?? ""); + WriteLine(" IndexFileSize: {0}", module.IndexFileSize?.ToString("X8") ?? ""); + WriteLine(" IndexTimeStamp: {0}", module.IndexTimeStamp?.ToString("X8") ?? ""); + WriteLine(" Version: {0}", module.GetVersionData()?.ToString() ?? ""); + string versionString = module.GetVersionString(); + if (!string.IsNullOrEmpty(versionString)) + { + WriteLine(" {0}", versionString); + } + foreach (PdbFileInfo pdbFileInfo in module.GetPdbFileInfos()) + { + WriteLine(" PdbInfo: {0}", pdbFileInfo); + } + WriteLine(" BuildId: {0}", !module.BuildId.IsDefaultOrEmpty ? string.Concat(module.BuildId.Select((b) => b.ToString("x2"))) : ""); + } + else + { + WriteLine("{0:X16} {1:X8} {2}", module.ImageBase, module.ImageSize, module.FileName); + } + if (Segment) + { + DisplaySegments(module); } - WriteLine("Total image size: {0}", totalSize); } public ITarget Target { get; set; } diff --git a/src/Microsoft.Diagnostics.TestHelpers/IProcessLogger.cs b/src/Microsoft.Diagnostics.TestHelpers/IProcessLogger.cs index 233372a1f5..f99080b752 100644 --- a/src/Microsoft.Diagnostics.TestHelpers/IProcessLogger.cs +++ b/src/Microsoft.Diagnostics.TestHelpers/IProcessLogger.cs @@ -15,6 +15,7 @@ public enum ProcessStream public enum KillReason { TimedOut, + Stopped, Unknown } diff --git a/src/Microsoft.Diagnostics.TestHelpers/ProcessRunner.cs b/src/Microsoft.Diagnostics.TestHelpers/ProcessRunner.cs index e5bca1393d..9bee89c895 100644 --- a/src/Microsoft.Diagnostics.TestHelpers/ProcessRunner.cs +++ b/src/Microsoft.Diagnostics.TestHelpers/ProcessRunner.cs @@ -29,7 +29,7 @@ namespace Microsoft.Diagnostics.TestHelpers /// only calls to Kill() and property getters invoked within the logging callbacks will be called /// asynchronously. /// - public class ProcessRunner + public class ProcessRunner : IDisposable { // All of the locals might accessed from multiple threads and need to read/written under // the _lock. We also use the lock to synchronize property access on the process object. @@ -232,6 +232,11 @@ public int ExitCode get { lock (_lock) { return _p.ExitCode; } } } + public int ModuleCount + { + get { lock (_lock) { return _p.Modules.Count; } } + } + public void StandardInputWriteLine(string line) { IProcessLogger[] loggers = null; @@ -246,6 +251,7 @@ public void StandardInputWriteLine(string line) logger.WriteLine(this, line, ProcessStream.StandardIn); } inputStream.WriteLine(line); + inputStream.Flush(); } public Task Run() @@ -262,6 +268,16 @@ public Task WaitForExit() } } + public void Dispose() + { + Process p = null; + lock (_lock) + { + p = _p; + } + p?.Dispose(); + } + public ProcessRunner Start() { Process p = null; diff --git a/src/Microsoft.Diagnostics.TestHelpers/TestConfiguration.cs b/src/Microsoft.Diagnostics.TestHelpers/TestConfiguration.cs index ece382ad0d..5aa681063e 100644 --- a/src/Microsoft.Diagnostics.TestHelpers/TestConfiguration.cs +++ b/src/Microsoft.Diagnostics.TestHelpers/TestConfiguration.cs @@ -454,6 +454,10 @@ private string GetStringViewWithVersion(string version) sb.Append("."); sb.Append(debuggeeBuildProcess); } + if (PublishSingleFile) + { + sb.Append(".singlefile"); + } if (!string.IsNullOrEmpty(version)) { sb.Append("."); @@ -781,6 +785,18 @@ public string LinkerPackageVersion get { return GetValue("LinkerPackageVersion"); } } + /// + /// The root of the dotnet install to use to run the test (i.e. $(RepoRootDir)/.dotnet-test) + /// + public string DotNetRoot + { + get + { + string dotnetRoot = GetValue("DotNetRoot"); + return MakeCanonicalPath(dotnetRoot); + } + } + #region Runtime Features properties /// diff --git a/src/Microsoft.Diagnostics.TestHelpers/TestOutputProcessLogger.cs b/src/Microsoft.Diagnostics.TestHelpers/TestOutputProcessLogger.cs index 6966668dd7..475d45398f 100644 --- a/src/Microsoft.Diagnostics.TestHelpers/TestOutputProcessLogger.cs +++ b/src/Microsoft.Diagnostics.TestHelpers/TestOutputProcessLogger.cs @@ -12,9 +12,9 @@ namespace Microsoft.Diagnostics.TestHelpers { public class TestOutputProcessLogger : IProcessLogger { - string _timeFormat = "mm\\:ss\\.fff"; - ITestOutputHelper _output; - StringBuilder[] _lineBuffers; + private static readonly string _timeFormat = "mm\\:ss\\.fff"; + private readonly ITestOutputHelper _output; + private readonly StringBuilder[] _lineBuffers; public TestOutputProcessLogger(ITestOutputHelper output) { @@ -69,7 +69,7 @@ public virtual void ProcessExited(ProcessRunner runner) { TimeSpan offset = runner.StartTime - DateTime.Now; _output.WriteLine("}"); - _output.WriteLine("Exit code: " + runner.ExitCode + " ( " + offset.ToString(_timeFormat) + " elapsed)"); + _output.WriteLine($"Process {runner.ProcessId} exited {runner.ExitCode} ({offset.ToString(_timeFormat)} elapsed)"); _output.WriteLine(""); } } @@ -79,16 +79,14 @@ public void ProcessKilled(ProcessRunner runner, KillReason reason) lock (this) { TimeSpan offset = runner.StartTime - DateTime.Now; - string reasonText = ""; - if (reason == KillReason.TimedOut) + string reasonText = reason switch { - reasonText = "Process timed out"; - } - else if (reason == KillReason.Unknown) - { - reasonText = "Kill() was called"; - } - _output.WriteLine(" Killing process: " + offset.ToString(_timeFormat) + ": " + reasonText); + KillReason.TimedOut => "Process timed out", + KillReason.Stopped => "Process was stopped", + KillReason.Unknown => "Kill() was called", + _ => "Reason Unknown" + }; + _output.WriteLine($"Killing process {runner.ProcessId}: {offset.ToString(_timeFormat)} - {reasonText}"); } } diff --git a/src/SOS/SOS.Hosting/SymbolServiceExtensions.cs b/src/SOS/SOS.Hosting/SymbolServiceExtensions.cs index 285b1cace5..2317f10981 100644 --- a/src/SOS/SOS.Hosting/SymbolServiceExtensions.cs +++ b/src/SOS/SOS.Hosting/SymbolServiceExtensions.cs @@ -120,18 +120,26 @@ public static int GetICorDebugMetadataLocator( { SymbolStoreKey key = PEFileKeyGenerator.GetKey(imagePath, imageTimestamp, imageSize); string localFilePath = symbolService.DownloadFile(key); - localFilePath += "\0"; // null terminate the string - actualSize = localFilePath.Length; - - if (pathBufferSize > actualSize) + if (!string.IsNullOrWhiteSpace(localFilePath)) { - Trace.TraceInformation($"GetICorDebugMetadataLocator: SUCCEEDED {localFilePath}"); - Marshal.Copy(localFilePath.ToCharArray(), 0, pwszPathBuffer, actualSize); + localFilePath += "\0"; // null terminate the string + actualSize = localFilePath.Length; + + if (pathBufferSize > actualSize) + { + Trace.TraceInformation($"GetICorDebugMetadataLocator: SUCCEEDED {localFilePath}"); + Marshal.Copy(localFilePath.ToCharArray(), 0, pwszPathBuffer, actualSize); + } + else + { + Trace.TraceError("GetICorDebugMetadataLocator: E_INSUFFICIENT_BUFFER"); + hr = E_INSUFFICIENT_BUFFER; + } } - else + else { - Trace.TraceError("GetICorDebugMetadataLocator: E_INSUFFICIENT_BUFFER"); - hr = E_INSUFFICIENT_BUFFER; + Trace.TraceError($"GetICorDebugMetadataLocator: {imagePath} {imageTimestamp:X8} {imageSize:X8} download FAILED"); + hr = HResult.E_FAIL; } } else diff --git a/src/SOS/SOS.UnitTests/ConfigFiles/Unix/Debugger.Tests.Config.txt b/src/SOS/SOS.UnitTests/ConfigFiles/Unix/Debugger.Tests.Config.txt index 38cab1529a..3e76b20f05 100644 --- a/src/SOS/SOS.UnitTests/ConfigFiles/Unix/Debugger.Tests.Config.txt +++ b/src/SOS/SOS.UnitTests/ConfigFiles/Unix/Debugger.Tests.Config.txt @@ -24,19 +24,19 @@ true false - - net6.0 + net7.0 net5.0 + net6.0 netcoreapp3.1 $(RepoRootDir)/src/SOS/SOS.UnitTests/Debuggees sdk.prebuilt $(RootBinDir) - - $(RepoRootDir)/.dotnet/dotnet + $(DotNetRoot)/dotnet + dotnet7=https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet7/nuget/v3/index.json; dotnet6=https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet6/nuget/v3/index.json; dotnet-core=https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json; dotnet-public=https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json @@ -50,7 +50,7 @@ cli $(RootBinDir)/Debuggees/SingleFile $(BuildProjectFrameworkLatest) - $(RuntimeVersionLatest) + $(SingleFileRuntimeLatestVersion) true @@ -66,9 +75,9 @@ $(RuntimeVersionLatest) $(DotNetRoot)/shared/Microsoft.NETCore.App/$(RuntimeFrameworkVersion) - + - - - + - + - $(InstallDir)/libdbgshim.so $(RuntimeModuleDir)/libcoreclr.so $(RuntimeModuleDir)/libmscordbi.so $(RuntimeModuleDir)/libmscordaccore.so $(InstallDir)\dbgshim.dll $(RuntimeModuleDir)\coreclr.dll $(RuntimeModuleDir)\mscordbi.dll diff --git a/src/tests/DbgShim.UnitTests/DebuggeeInfo.cs b/src/tests/DbgShim.UnitTests/DebuggeeInfo.cs index 3ac8d3d4cd..5bcd43986b 100644 --- a/src/tests/DbgShim.UnitTests/DebuggeeInfo.cs +++ b/src/tests/DbgShim.UnitTests/DebuggeeInfo.cs @@ -77,7 +77,7 @@ public async Task WaitForDebuggee() await _pipeServer.WaitForConnectionAsync(source.Token); Trace.TraceInformation($"DebuggeeInfo.WaitForDebuggee: after wait {ProcessId}"); } - catch (OperationCanceledException ex) + catch (Exception ex) when (ex is TaskCanceledException || ex is OperationCanceledException) { Trace.TraceError($"DebuggeeInfo.WaitForDebuggee: canceled {ex}"); return false; diff --git a/src/tests/DbgShim.UnitTests/Debuggees/SimpleDebuggee/SimpleDebuggee.cs b/src/tests/DbgShim.UnitTests/Debuggees/SimpleDebuggee/SimpleDebuggee.cs index 0e870ae3e1..8be1fbab04 100644 --- a/src/tests/DbgShim.UnitTests/Debuggees/SimpleDebuggee/SimpleDebuggee.cs +++ b/src/tests/DbgShim.UnitTests/Debuggees/SimpleDebuggee/SimpleDebuggee.cs @@ -16,12 +16,11 @@ public static int Main(string[] args) { try { - int timeout = TimeSpan.FromMinutes(5).Milliseconds; using var pipeStream = new NamedPipeClientStream(pipeServerName); Console.WriteLine("{0} SimpleDebuggee: connecting to pipe", pid); Console.Out.Flush(); - pipeStream.Connect(timeout); + pipeStream.Connect((int)TimeSpan.FromMinutes(5).TotalMilliseconds); Console.WriteLine("{0} SimpleDebuggee: connected to pipe", pid); Console.Out.Flush(); diff --git a/src/tests/Directory.Build.props b/src/tests/Directory.Build.props new file mode 100644 index 0000000000..eaf4b4e2f5 --- /dev/null +++ b/src/tests/Directory.Build.props @@ -0,0 +1,16 @@ + + + + + $(Platform) + $([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture.ToString().ToLowerInvariant) + + + true + false + + netcoreapp3.1;net6.0;net7.0 + net6.0;net7.0 + + + diff --git a/src/tests/EventPipeTracee/EventPipeTracee.csproj b/src/tests/EventPipeTracee/EventPipeTracee.csproj index 1b898c05dc..0d7605719e 100644 --- a/src/tests/EventPipeTracee/EventPipeTracee.csproj +++ b/src/tests/EventPipeTracee/EventPipeTracee.csproj @@ -2,7 +2,7 @@ Exe $(BuildProjectFramework) - netcoreapp3.1;net5.0 + netcoreapp3.1;net6.0;net7.0 diff --git a/src/tests/EventPipeTracee/Program.cs b/src/tests/EventPipeTracee/Program.cs index 0daa16664f..752c803ea7 100644 --- a/src/tests/EventPipeTracee/Program.cs +++ b/src/tests/EventPipeTracee/Program.cs @@ -6,6 +6,8 @@ using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; +using System.Diagnostics; +using System.IO.Pipes; using System.Linq; namespace EventPipeTracee @@ -14,16 +16,29 @@ class Program { private const string AppLoggerCategoryName = "AppLoggerCategory"; - static void Main(string[] args) + public static int Main(string[] args) { - bool spinWait10 = args.Length > 1 && "SpinWait10".Equals(args[1], StringComparison.Ordinal); - TestBody(args[0], spinWait10); - } + int pid = Process.GetCurrentProcess().Id; + string pipeServerName = args.Length > 0 ? args[0] : null; + if (pipeServerName == null) + { + Console.Error.WriteLine($"{pid} EventPipeTracee: no pipe name"); + Console.Error.Flush(); + return -1; + } + using var pipeStream = new NamedPipeClientStream(pipeServerName); + bool spinWait10 = args.Length > 2 && "SpinWait10".Equals(args[2], StringComparison.Ordinal); + string loggerCategory = args[1]; - private static void TestBody(string loggerCategory, bool spinWait10) - { - Console.Error.WriteLine("Starting remote test process"); - Console.Error.Flush(); + Console.WriteLine($"{pid} EventPipeTracee: start process"); + Console.Out.Flush(); + + // Signal that the tracee has started + Console.WriteLine($"{pid} EventPipeTracee: connecting to pipe"); + Console.Out.Flush(); + pipeStream.Connect(5 * 60 * 1000); + Console.WriteLine($"{pid} EventPipeTracee: connected to pipe"); + Console.Out.Flush(); ServiceCollection serviceCollection = new ServiceCollection(); serviceCollection.AddLogging(builder => @@ -38,19 +53,20 @@ private static void TestBody(string loggerCategory, bool spinWait10) var customCategoryLogger = loggerFactory.CreateLogger(loggerCategory); var appCategoryLogger = loggerFactory.CreateLogger(AppLoggerCategoryName); - Console.Error.WriteLine($"{DateTime.UtcNow} Awaiting start"); - Console.Error.Flush(); - if (Console.Read() == -1) - { - throw new InvalidOperationException("Unable to receive start signal"); - } + Console.WriteLine($"{pid} EventPipeTracee: {DateTime.UtcNow} Awaiting start"); + Console.Out.Flush(); + + // Wait for server to send something + int input = pipeStream.ReadByte(); + + Console.WriteLine($"{pid} {DateTime.UtcNow} Starting test body '{input}'"); + Console.Out.Flush(); - Console.Error.WriteLine($"{DateTime.UtcNow} Starting test body"); - Console.Error.Flush(); TestBodyCore(customCategoryLogger, appCategoryLogger); - //Signal end of test data - Console.WriteLine("1"); + Console.WriteLine($"{pid} EventPipeTracee: signal end of test data"); + Console.Out.Flush(); + pipeStream.WriteByte(31); if (spinWait10) { @@ -62,22 +78,22 @@ private static void TestBody(string loggerCategory, bool spinWait10) acc++; if (acc % 1_000_000 == 0) { - Console.Error.WriteLine("Spin waiting..."); + Console.WriteLine($"{pid} Spin waiting..."); } } } - Console.Error.WriteLine($"{DateTime.UtcNow} Awaiting end"); - Console.Error.Flush(); - if (Console.Read() == -1) - { - throw new InvalidOperationException("Unable to receive end signal"); - } + Console.WriteLine($"{pid} {DateTime.UtcNow} Awaiting end"); + Console.Out.Flush(); + + // Wait for server to send something + input = pipeStream.ReadByte(); - Console.Error.WriteLine($"{DateTime.UtcNow} Ending remote test process"); + Console.WriteLine($"{pid} EventPipeTracee {DateTime.UtcNow} Ending remote test process '{input}'"); + return 0; } - //TODO At some point we may want parameters to choose different test bodies. + // TODO At some point we may want parameters to choose different test bodies. private static void TestBodyCore(ILogger customCategoryLogger, ILogger appCategoryLogger) { //Json data is always converted to strings for ActivityStart events. diff --git a/src/tests/ExitCodeTracee/ExitCodeTracee.csproj b/src/tests/ExitCodeTracee/ExitCodeTracee.csproj index cd0510ad22..6b634ef181 100644 --- a/src/tests/ExitCodeTracee/ExitCodeTracee.csproj +++ b/src/tests/ExitCodeTracee/ExitCodeTracee.csproj @@ -2,6 +2,6 @@ Exe $(BuildProjectFramework) - netcoreapp3.1;net5.0 + netcoreapp3.1;net6.0;net7.0 diff --git a/src/tests/Microsoft.Diagnostics.DebugServices.UnitTests/Microsoft.Diagnostics.DebugServices.UnitTests.csproj b/src/tests/Microsoft.Diagnostics.DebugServices.UnitTests/Microsoft.Diagnostics.DebugServices.UnitTests.csproj index d41a2bd2d9..ed9a4290f1 100644 --- a/src/tests/Microsoft.Diagnostics.DebugServices.UnitTests/Microsoft.Diagnostics.DebugServices.UnitTests.csproj +++ b/src/tests/Microsoft.Diagnostics.DebugServices.UnitTests/Microsoft.Diagnostics.DebugServices.UnitTests.csproj @@ -1,8 +1,7 @@  - - netcoreapp3.1 + net6.0 $(OutputPath)$(TargetFramework)\Debugger.Tests.Common.txt 1.0.257801 diff --git a/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventCounterPipelineUnitTests.cs b/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventCounterPipelineUnitTests.cs index cf7cc8e976..bfb15c6b6b 100644 --- a/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventCounterPipelineUnitTests.cs +++ b/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventCounterPipelineUnitTests.cs @@ -3,14 +3,15 @@ // See the LICENSE file in the project root for more information. using Microsoft.Diagnostics.NETCore.Client; -using Microsoft.Diagnostics.NETCore.Client.UnitTests; -using System; +using Microsoft.Diagnostics.TestHelpers; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Xunit; using Xunit.Abstractions; +using Xunit.Extensions; +using TestRunner = Microsoft.Diagnostics.CommonTestRunner.TestRunner; namespace Microsoft.Diagnostics.Monitoring.EventPipe.UnitTests { @@ -18,6 +19,8 @@ public class EventCounterPipelineUnitTests { private readonly ITestOutputHelper _output; + public static IEnumerable Configurations => TestRunner.Configurations; + public EventCounterPipelineUnitTests(ITestOutputHelper output) { _output = output; @@ -83,8 +86,8 @@ private static string CreateKey(string providerName, string counterName) } } - [Fact] - public async Task TestCounterEventPipeline() + [SkippableTheory, MemberData(nameof(Configurations))] + public async Task TestCounterEventPipeline(TestConfiguration config) { var expectedCounters = new[] { "cpu-usage", "working-set" }; string expectedProvider = "System.Runtime"; @@ -96,11 +99,9 @@ public async Task TestCounterEventPipeline() var logger = new TestMetricsLogger(expectedMap, foundExpectedCountersSource); - await using (var testExecution = StartTraceeProcess("CounterRemoteTest")) + await using (var testRunner = await PipelineTestUtilities.StartProcess(config, "CounterRemoteTest", _output)) { - //TestRunner should account for start delay to make sure that the diagnostic pipe is available. - - var client = new DiagnosticsClient(testExecution.TestRunner.Pid); + var client = new DiagnosticsClient(testRunner.Pid); await using EventCounterPipeline pipeline = new EventCounterPipeline(client, new EventPipeCounterPipelineSettings { @@ -116,10 +117,9 @@ public async Task TestCounterEventPipeline() CounterIntervalSeconds = 1 }, new[] { logger }); - await PipelineTestUtilities.ExecutePipelineWithDebugee( - _output, + await PipelineTestUtilities.ExecutePipelineWithTracee( pipeline, - testExecution, + testRunner, foundExpectedCountersSource); } @@ -130,10 +130,5 @@ await PipelineTestUtilities.ExecutePipelineWithDebugee( Assert.Equal(expectedCounters, actualMetrics); Assert.True(logger.Metrics.All(m => string.Equals(m.Provider, expectedProvider))); } - - private RemoteTestExecution StartTraceeProcess(string loggerCategory) - { - return RemoteTestExecution.StartProcess(CommonHelper.GetTraceePathWithArgs("EventPipeTracee") + " " + loggerCategory, _output); - } } } diff --git a/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventCounterTriggerTests.cs b/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventCounterTriggerTests.cs index 257b6b078c..4b6fd60137 100644 --- a/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventCounterTriggerTests.cs +++ b/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventCounterTriggerTests.cs @@ -5,8 +5,9 @@ using Microsoft.Diagnostics.Monitoring.EventPipe.Triggers.EventCounter; using Microsoft.Diagnostics.Monitoring.EventPipe.Triggers.Pipelines; using Microsoft.Diagnostics.NETCore.Client; -using Microsoft.Diagnostics.NETCore.Client.UnitTests; +using Microsoft.Diagnostics.TestHelpers; using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Globalization; using System.Runtime.InteropServices; @@ -15,6 +16,7 @@ using Xunit; using Xunit.Abstractions; using Xunit.Extensions; +using TestRunner = Microsoft.Diagnostics.CommonTestRunner.TestRunner; namespace Microsoft.Diagnostics.Monitoring.EventPipe.UnitTests { @@ -22,6 +24,8 @@ public class EventCounterTriggerTests { private readonly ITestOutputHelper _output; + public static IEnumerable Configurations => TestRunner.Configurations; + public EventCounterTriggerTests(ITestOutputHelper output) { _output = output; @@ -315,12 +319,12 @@ public void EventCounterTriggerDropTest() /// Tests that the trigger condition can be detected on a live application /// using the EventPipeTriggerPipeline. /// - [SkippableFact] - public async Task EventCounterTriggerWithEventPipePipelineTest() + [SkippableTheory, MemberData(nameof(Configurations))] + public async Task EventCounterTriggerWithEventPipePipelineTest(TestConfiguration config) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && config.RuntimeFrameworkVersionMajor < 5) { - throw new SkipTestException("https://github.com/dotnet/diagnostics/issues/2568"); + throw new SkipTestException("Unreliable on Linux .NET 3.1"); } EventCounterTriggerSettings settings = new() { @@ -331,11 +335,9 @@ public async Task EventCounterTriggerWithEventPipePipelineTest() CounterIntervalSeconds = 1 }; - await using (var testExecution = StartTraceeProcess("TriggerRemoteTest")) + await using (var testRunner = await PipelineTestUtilities.StartProcess(config, "TriggerRemoteTest SpinWait10", _output, testProcessTimeout: 2 * 60 * 1000)) { - //TestRunner should account for start delay to make sure that the diagnostic pipe is available. - - DiagnosticsClient client = new(testExecution.TestRunner.Pid); + DiagnosticsClient client = new(testRunner.Pid); TaskCompletionSource waitSource = new(TaskCreationOptions.RunContinuationsAsynchronously); @@ -353,10 +355,9 @@ public async Task EventCounterTriggerWithEventPipePipelineTest() waitSource.TrySetResult(null); }); - await PipelineTestUtilities.ExecutePipelineWithDebugee( - _output, + await PipelineTestUtilities.ExecutePipelineWithTracee( pipeline, - testExecution, + testRunner, waitSource); Assert.True(waitSource.Task.IsCompletedSuccessfully); @@ -404,11 +405,6 @@ private void SimulateDataVerifyTrigger(EventCounterTriggerSettings settings, Cpu } } - private RemoteTestExecution StartTraceeProcess(string loggerCategory) - { - return RemoteTestExecution.StartProcess(CommonHelper.GetTraceePathWithArgs("EventPipeTracee") + " " + loggerCategory + " SpinWait10", _output); - } - private sealed class CpuData { public CpuData(double value, bool? result, bool drop = false) diff --git a/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventLogsPipelineUnitTests.cs b/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventLogsPipelineUnitTests.cs index a53777ed37..abd792d9f4 100644 --- a/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventLogsPipelineUnitTests.cs +++ b/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventLogsPipelineUnitTests.cs @@ -2,8 +2,9 @@ // 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.CommonTestRunner; using Microsoft.Diagnostics.NETCore.Client; -using Microsoft.Diagnostics.NETCore.Client.UnitTests; +using Microsoft.Diagnostics.TestHelpers; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; @@ -15,6 +16,7 @@ using Xunit; using Xunit.Abstractions; using Xunit.Extensions; +using TestRunner = Microsoft.Diagnostics.CommonTestRunner.TestRunner; namespace Microsoft.Diagnostics.Monitoring.EventPipe.UnitTests { @@ -26,6 +28,8 @@ public class EventLogsPipelineUnitTests private readonly ITestOutputHelper _output; + public static IEnumerable Configurations => TestRunner.Configurations; + public EventLogsPipelineUnitTests(ITestOutputHelper output) { _output = output; @@ -34,15 +38,10 @@ public EventLogsPipelineUnitTests(ITestOutputHelper output) /// /// Test that all log events are collected if no filters are specified. /// - [SkippableFact] - public async Task TestLogsAllCategoriesAllLevels() + [SkippableTheory, MemberData(nameof(Configurations))] + public async Task TestLogsAllCategoriesAllLevels(TestConfiguration config) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - throw new SkipTestException("https://github.com/dotnet/diagnostics/issues/2541"); - } - - using Stream outputStream = await GetLogsAsync(settings => + using Stream outputStream = await GetLogsAsync(config, settings => { settings.UseAppFilters = false; }); @@ -63,15 +62,10 @@ public async Task TestLogsAllCategoriesAllLevels() /// /// Test that log events at or above the default level are collected. /// - [SkippableFact] - public async Task TestLogsAllCategoriesDefaultLevel() + [SkippableTheory, MemberData(nameof(Configurations))] + public async Task TestLogsAllCategoriesDefaultLevel(TestConfiguration config) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - throw new SkipTestException("https://github.com/dotnet/diagnostics/issues/2541"); - } - - using Stream outputStream = await GetLogsAsync(settings => + using Stream outputStream = await GetLogsAsync(config, settings => { settings.UseAppFilters = false; settings.LogLevel = LogLevel.Warning; @@ -91,15 +85,10 @@ public async Task TestLogsAllCategoriesDefaultLevel() /// /// Test that log events at the default level are collected for categories without a specified level. /// - [SkippableFact] - public async Task TestLogsAllCategoriesDefaultLevelFallback() + [SkippableTheory, MemberData(nameof(Configurations))] + public async Task TestLogsAllCategoriesDefaultLevelFallback(TestConfiguration config) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - throw new SkipTestException("https://github.com/dotnet/diagnostics/issues/2541"); - } - - using Stream outputStream = await GetLogsAsync(settings => + using Stream outputStream = await GetLogsAsync(config, settings => { settings.UseAppFilters = false; settings.LogLevel = LogLevel.Error; @@ -124,12 +113,13 @@ public async Task TestLogsAllCategoriesDefaultLevelFallback() /// /// Test that LogLevel.None is not supported as the default log level. /// - [Fact] - public async Task TestLogsAllCategoriesDefaultLevelNoneNotSupported() + [SkippableTheory, MemberData(nameof(Configurations))] + public async Task TestLogsAllCategoriesDefaultLevelNoneNotSupported(TestConfiguration config) { // Pipeline should throw PipelineException with inner exception of NotSupportedException. PipelineException exception = await Assert.ThrowsAsync( () => GetLogsAsync( + config, settings => { settings.UseAppFilters = false; @@ -142,10 +132,10 @@ public async Task TestLogsAllCategoriesDefaultLevelNoneNotSupported() /// /// Test that log events are collected for the categories and levels specified by the application. /// - [Fact] - public async Task TestLogsUseAppFilters() + [SkippableTheory, MemberData(nameof(Configurations))] + public async Task TestLogsUseAppFilters(TestConfiguration config) { - using Stream outputStream = await GetLogsAsync(); + using Stream outputStream = await GetLogsAsync(config); Assert.True(outputStream.Length > 0, "No data written by logging process."); @@ -161,15 +151,10 @@ public async Task TestLogsUseAppFilters() /// Test that log events are collected for the categories and levels specified by the application /// and for the categories and levels specified in the filter specs. /// - [SkippableFact] - public async Task TestLogsUseAppFiltersAndFilterSpecs() + [SkippableTheory, MemberData(nameof(Configurations))] + public async Task TestLogsUseAppFiltersAndFilterSpecs(TestConfiguration config) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - throw new SkipTestException("https://github.com/dotnet/diagnostics/issues/2541"); - } - - using Stream outputStream = await GetLogsAsync(settings => + using Stream outputStream = await GetLogsAsync(config, settings => { settings.FilterSpecs = new Dictionary() { @@ -191,14 +176,10 @@ public async Task TestLogsUseAppFiltersAndFilterSpecs() /// /// Test that log events are collected for wildcard categories. /// - [SkippableFact] - public async Task TestLogsWildcardCategory() + [SkippableTheory, MemberData(nameof(Configurations))] + public async Task TestLogsWildcardCategory(TestConfiguration config) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - throw new SkipTestException("https://github.com/dotnet/diagnostics/issues/2568"); - } - using Stream outputStream = await GetLogsAsync(settings => + using Stream outputStream = await GetLogsAsync(config, settings => { settings.UseAppFilters = false; settings.LogLevel = LogLevel.Critical; @@ -219,16 +200,14 @@ public async Task TestLogsWildcardCategory() Assert.True(reader.EndOfStream, "Expected to have read all entries from stream."); } - private async Task GetLogsAsync(Action settingsCallback = null) + private async Task GetLogsAsync(TestConfiguration config, Action settingsCallback = null) { var outputStream = new MemoryStream(); - await using (var testExecution = StartTraceeProcess(LoggerRemoteTestName)) + await using (var testRunner = await PipelineTestUtilities.StartProcess(config, LoggerRemoteTestName, _output)) { - //TestRunner should account for start delay to make sure that the diagnostic pipe is available. - using var loggerFactory = new LoggerFactory(new[] { new TestStreamingLoggerProvider(outputStream) }); - var client = new DiagnosticsClient(testExecution.TestRunner.Pid); + var client = new DiagnosticsClient(testRunner.Pid); var logSettings = new EventLogsPipelineSettings { Duration = Timeout.InfiniteTimeSpan }; if (null != settingsCallback) @@ -237,7 +216,7 @@ private async Task GetLogsAsync(Action settin } await using var pipeline = new EventLogsPipeline(client, logSettings, loggerFactory); - await PipelineTestUtilities.ExecutePipelineWithDebugee(_output, pipeline, testExecution); + await PipelineTestUtilities.ExecutePipelineWithTracee(pipeline, testRunner); } outputStream.Position = 0L; @@ -335,11 +314,6 @@ private static void Validate(IDictionary values, params (st } } - private RemoteTestExecution StartTraceeProcess(string loggerCategory) - { - return RemoteTestExecution.StartProcess(CommonHelper.GetTraceePathWithArgs("EventPipeTracee") + " " + loggerCategory, _output); - } - private sealed class LoggerTestResult { public string Category { get; set; } diff --git a/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventTracePipelineUnitTests.cs b/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventTracePipelineUnitTests.cs index 13dd2bbb80..8c88286e28 100644 --- a/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventTracePipelineUnitTests.cs +++ b/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/EventTracePipelineUnitTests.cs @@ -2,22 +2,20 @@ // 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.CommonTestRunner; +using Microsoft.Diagnostics.NETCore.Client; +using Microsoft.Diagnostics.TestHelpers; +using Microsoft.Diagnostics.Tracing; using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; -using System.Linq; using System.Runtime.InteropServices; -using System.Text.Json; using System.Threading; using System.Threading.Tasks; -using Microsoft.Diagnostics.NETCore.Client; -using Microsoft.Diagnostics.NETCore.Client.UnitTests; -using Microsoft.Diagnostics.Tracing; -using Microsoft.Extensions.Logging; using Xunit; using Xunit.Abstractions; using Xunit.Extensions; +using TestRunner = Microsoft.Diagnostics.CommonTestRunner.TestRunner; namespace Microsoft.Diagnostics.Monitoring.EventPipe.UnitTests { @@ -25,20 +23,20 @@ public class EventTracePipelineUnitTests { private readonly ITestOutputHelper _output; + public static IEnumerable Configurations => TestRunner.Configurations; + public EventTracePipelineUnitTests(ITestOutputHelper output) { _output = output; } - [Fact] - public async Task TestTraceStopAsync() + [SkippableTheory, MemberData(nameof(Configurations))] + public async Task TestTraceStopAsync(TestConfiguration config) { Stream eventStream = null; - await using (var testExecution = StartTraceeProcess("TraceStopTest")) + await using (var testRunner = await PipelineTestUtilities.StartProcess(config, "TraceStopTest", _output)) { - //TestRunner should account for start delay to make sure that the diagnostic pipe is available. - - var client = new DiagnosticsClient(testExecution.TestRunner.Pid); + var client = new DiagnosticsClient(testRunner.Pid); var settings = new EventTracePipelineSettings() { Duration = Timeout.InfiniteTimeSpan, @@ -67,10 +65,9 @@ public async Task TestTraceStopAsync() await Task.Run(() => Assert.True(eventSource.Process()), token); }); - await PipelineTestUtilities.ExecutePipelineWithDebugee( - _output, + await PipelineTestUtilities.ExecutePipelineWithTracee( pipeline, - testExecution, + testRunner, foundProviderSource); } @@ -78,21 +75,19 @@ await PipelineTestUtilities.ExecutePipelineWithDebugee( Assert.Throws(() => eventStream.Read(new byte[4], 0, 4)); } - [SkippableFact] - public async Task TestEventStreamCleanup() + [SkippableTheory, MemberData(nameof(Configurations))] + public async Task TestEventStreamCleanup(TestConfiguration config) { if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - throw new SkipTestException("Test debugee sigfaults for OSX/Linux"); + throw new SkipTestException("Test tracee sigfaults for OSX/Linux"); } Stream eventStream = null; using var cancellationTokenSource = new CancellationTokenSource(); - await using (var testExecution = StartTraceeProcess("TestEventStreamCleanup")) + await using (var testRunner = await PipelineTestUtilities.StartProcess(config, "TestEventStreamCleanup", _output)) { - //TestRunner should account for start delay to make sure that the diagnostic pipe is available. - - var client = new DiagnosticsClient(testExecution.TestRunner.Pid); + var client = new DiagnosticsClient(testRunner.Pid); var settings = new EventTracePipelineSettings() { Duration = Timeout.InfiniteTimeSpan, @@ -108,20 +103,14 @@ public async Task TestEventStreamCleanup() }); await Assert.ThrowsAsync( - async () => await PipelineTestUtilities.ExecutePipelineWithDebugee( - _output, + async () => await PipelineTestUtilities.ExecutePipelineWithTracee( pipeline, - testExecution, + testRunner, cancellationTokenSource.Token)); } //Validate that the stream is only valid for the lifetime of the callback in the trace pipeline. Assert.Throws(() => eventStream.Read(new byte[4], 0, 4)); } - - private RemoteTestExecution StartTraceeProcess(string loggerCategory) - { - return RemoteTestExecution.StartProcess(CommonHelper.GetTraceePathWithArgs("EventPipeTracee") + " " + loggerCategory, _output); - } } } diff --git a/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/Microsoft.Diagnostics.Monitoring.EventPipe.UnitTests.csproj b/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/Microsoft.Diagnostics.Monitoring.EventPipe.UnitTests.csproj index 8410ef25cd..2b066212c5 100644 --- a/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/Microsoft.Diagnostics.Monitoring.EventPipe.UnitTests.csproj +++ b/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/Microsoft.Diagnostics.Monitoring.EventPipe.UnitTests.csproj @@ -1,16 +1,13 @@  - netcoreapp3.1;net5.0 + $(UnitTestTargetFrameworks) - - - false - + diff --git a/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/PipelineTestUtilities.cs b/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/PipelineTestUtilities.cs index bc7992542a..4941ff9ecd 100644 --- a/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/PipelineTestUtilities.cs +++ b/src/tests/Microsoft.Diagnostics.Monitoring.EventPipe/PipelineTestUtilities.cs @@ -2,84 +2,85 @@ // 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.NETCore.Client.UnitTests; +using Microsoft.Diagnostics.TestHelpers; using System; using System.Threading; using System.Threading.Tasks; using Xunit.Abstractions; +using TestRunner = Microsoft.Diagnostics.CommonTestRunner.TestRunner; namespace Microsoft.Diagnostics.Monitoring.EventPipe.UnitTests { internal static class PipelineTestUtilities { - private static readonly TimeSpan DefaultPipelineRunTimeout = TimeSpan.FromMinutes(1); + private static readonly TimeSpan DefaultPipelineRunTimeout = TimeSpan.FromMinutes(2); - public static async Task ExecutePipelineWithDebugee( - ITestOutputHelper outputHelper, + public static async Task StartProcess(TestConfiguration config, string testArguments, ITestOutputHelper outputHelper, int testProcessTimeout = 60_000) + { + TestRunner runner = await TestRunner.Create(config, outputHelper, "EventPipeTracee", testArguments); + await runner.Start(testProcessTimeout); + return runner; + } + + public static async Task ExecutePipelineWithTracee( Pipeline pipeline, - RemoteTestExecution testExecution, + TestRunner testRunner, TaskCompletionSource waitTaskSource = null) { using var cancellation = new CancellationTokenSource(DefaultPipelineRunTimeout); - await ExecutePipelineWithDebugee( - outputHelper, + await ExecutePipelineWithTracee( pipeline, - testExecution, + testRunner, cancellation.Token, waitTaskSource); } - public static async Task ExecutePipelineWithDebugee( - ITestOutputHelper outputHelper, + public static async Task ExecutePipelineWithTracee( EventSourcePipeline pipeline, - RemoteTestExecution testExecution, + TestRunner testRunner, TaskCompletionSource waitTaskSource = null) where T : EventSourcePipelineSettings { using var cancellation = new CancellationTokenSource(DefaultPipelineRunTimeout); - await ExecutePipelineWithDebugee( - outputHelper, + await ExecutePipelineWithTracee( pipeline, (p, t) => p.StartAsync(t), - testExecution, + testRunner, cancellation.Token, waitTaskSource); } - public static Task ExecutePipelineWithDebugee( - ITestOutputHelper outputHelper, + public static Task ExecutePipelineWithTracee( Pipeline pipeline, - RemoteTestExecution testExecution, + TestRunner testRunner, CancellationToken token, TaskCompletionSource waitTaskSource = null) { - return ExecutePipelineWithDebugee( - outputHelper, + return ExecutePipelineWithTracee( pipeline, (p, t) => Task.FromResult(p.RunAsync(t)), - testExecution, + testRunner, token, waitTaskSource); } - private static async Task ExecutePipelineWithDebugee( - ITestOutputHelper outputHelper, + private static async Task ExecutePipelineWithTracee( TPipeline pipeline, Func> startPipelineAsync, - RemoteTestExecution testExecution, + TestRunner testRunner, CancellationToken token, TaskCompletionSource waitTaskSource = null) where TPipeline : Pipeline { Task runTask = await startPipelineAsync(pipeline, token); - //Begin event production - testExecution.SendSignal(); + // Begin event production + testRunner.WakeupTracee(); - //Wait for event production to be done - testExecution.WaitForSignal(); + // Wait for event production to be done + testRunner.WaitForSignal(); try { @@ -88,7 +89,7 @@ private static async Task ExecutePipelineWithDebugee( { using var _ = token.Register(() => { - outputHelper.WriteLine("Did not receive completion signal before cancellation."); + testRunner.WriteLine("Did not receive completion signal before cancellation."); waitTaskSource.TrySetCanceled(token); }); @@ -103,8 +104,8 @@ private static async Task ExecutePipelineWithDebugee( } finally { - //Signal for debugee that's ok to end/move on. - testExecution.SendSignal(); + // Signal for debugee that's ok to end/move on. + testRunner.WakeupTracee(); } } } diff --git a/src/tests/Microsoft.Diagnostics.Monitoring/Microsoft.Diagnostics.Monitoring.UnitTests.csproj b/src/tests/Microsoft.Diagnostics.Monitoring/Microsoft.Diagnostics.Monitoring.UnitTests.csproj index a7ee91a2ff..7b2263b52e 100644 --- a/src/tests/Microsoft.Diagnostics.Monitoring/Microsoft.Diagnostics.Monitoring.UnitTests.csproj +++ b/src/tests/Microsoft.Diagnostics.Monitoring/Microsoft.Diagnostics.Monitoring.UnitTests.csproj @@ -1,17 +1,13 @@  - netcoreapp3.1;net5.0 + $(UnitTestTargetFrameworks) - - - false - diff --git a/src/tests/Microsoft.Diagnostics.Monitoring/PipelineTests.cs b/src/tests/Microsoft.Diagnostics.Monitoring/PipelineTests.cs index 227e4a2927..eab58c889f 100644 --- a/src/tests/Microsoft.Diagnostics.Monitoring/PipelineTests.cs +++ b/src/tests/Microsoft.Diagnostics.Monitoring/PipelineTests.cs @@ -2,11 +2,7 @@ // 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; diff --git a/src/tests/Microsoft.Diagnostics.NETCore.Client/CommonHelper.cs b/src/tests/Microsoft.Diagnostics.NETCore.Client/CommonHelper.cs deleted file mode 100644 index 965759bc5e..0000000000 --- a/src/tests/Microsoft.Diagnostics.NETCore.Client/CommonHelper.cs +++ /dev/null @@ -1,42 +0,0 @@ -// 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.IO; -using System.Runtime.InteropServices; - -namespace Microsoft.Diagnostics.NETCore.Client -{ - public partial class CommonHelper - { - public static string HostExe = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? - (RuntimeInformation.ProcessArchitecture == Architecture.X86 ? - "..\\..\\..\\..\\..\\.dotnet\\x86\\dotnet.exe" : - "..\\..\\..\\..\\..\\.dotnet\\dotnet.exe") : - "../../../../../.dotnet/dotnet"; - - /// - /// gets the tracee path, with args for the dotnet host for finding the correct version of the runtime.!-- - /// example: "--fx-version 5.0.0-rc.1.12345.12 /path/to/tracee" - /// - public static string GetTraceePathWithArgs(string traceeName = "Tracee", string targetFramework = "netcoreapp3.1") - { - var curPath = Directory.GetCurrentDirectory(); - - var traceePath = curPath - .Replace(System.Reflection.Assembly.GetCallingAssembly().GetName().Name, traceeName) - .Replace("netcoreapp3.1", targetFramework); - - traceePath = Path.Combine(traceePath, Path.ChangeExtension(traceeName, ".dll")); - - - // CurrentDARCVersion is generated at build time by Microsoft.Diagnostics.NETCore.Client.UnitTests.csproj - // This value will be set to whatever the value for the newest runtime in eng/Versions.Props is - if (targetFramework.Equals("net5.0", StringComparison.InvariantCultureIgnoreCase)) - traceePath = $"--fx-version {CurrentDARCVersion} {traceePath}"; - - return traceePath; - } - } -} \ No newline at end of file diff --git a/src/tests/Microsoft.Diagnostics.NETCore.Client/EventPipeSessionTests.cs b/src/tests/Microsoft.Diagnostics.NETCore.Client/EventPipeSessionTests.cs index 8a761289ca..1a3c39212e 100644 --- a/src/tests/Microsoft.Diagnostics.NETCore.Client/EventPipeSessionTests.cs +++ b/src/tests/Microsoft.Diagnostics.NETCore.Client/EventPipeSessionTests.cs @@ -2,6 +2,8 @@ // 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.CommonTestRunner; +using Microsoft.Diagnostics.TestHelpers; using Microsoft.Diagnostics.Tracing; using System; using System.Collections.Generic; @@ -9,71 +11,72 @@ using System.Threading.Tasks; using Xunit; using Xunit.Abstractions; +using Xunit.Extensions; +using TestRunner = Microsoft.Diagnostics.CommonTestRunner.TestRunner; namespace Microsoft.Diagnostics.NETCore.Client { public class EventPipeSessionTests { - private readonly ITestOutputHelper output; + private readonly ITestOutputHelper _output; + + public static IEnumerable Configurations => TestRunner.Configurations; public EventPipeSessionTests(ITestOutputHelper outputHelper) { - output = outputHelper; + _output = outputHelper; } - [Fact] - public Task BasicEventPipeSessionTest() + [SkippableTheory, MemberData(nameof(Configurations))] + public Task BasicEventPipeSessionTest(TestConfiguration config) { - return BasicEventPipeSessionTestCore(useAsync: false); + return BasicEventPipeSessionTestCore(config, useAsync: false); } - [Fact] - public Task BasicEventPipeSessionTestAsync() + [SkippableTheory, MemberData(nameof(Configurations))] + public Task BasicEventPipeSessionTestAsync(TestConfiguration config) { - return BasicEventPipeSessionTestCore(useAsync: true); + return BasicEventPipeSessionTestCore(config, useAsync: true); } /// /// A simple test that checks if we can create an EventPipeSession on a child process /// - private async Task BasicEventPipeSessionTestCore(bool useAsync) - + private async Task BasicEventPipeSessionTestCore(TestConfiguration config, bool useAsync) { - using TestRunner runner = new TestRunner(CommonHelper.GetTraceePathWithArgs(), output); - runner.Start(timeoutInMSPipeCreation: 15_000, testProcessTimeout: 60_000); + await using TestRunner runner = await TestRunner.Create(config, _output, "Tracee"); + await runner.Start(testProcessTimeout: 60_000); DiagnosticsClientApiShim clientShim = new DiagnosticsClientApiShim(new DiagnosticsClient(runner.Pid), useAsync); - using (var session = await clientShim.StartEventPipeSession(new List() + // Don't dispose of the session here because it unnecessarily hangs the test for 30 secs + EventPipeSession session = await clientShim.StartEventPipeSession(new List() { new EventPipeProvider("Microsoft-Windows-DotNETRuntime", EventLevel.Informational) - })) - { - Assert.True(session.EventStream != null); - } + }); + Assert.True(session.EventStream != null); runner.Stop(); } - [Fact] - public Task EventPipeSessionStreamTest() + [SkippableTheory, MemberData(nameof(Configurations))] + public Task EventPipeSessionStreamTest(TestConfiguration config) { - return EventPipeSessionStreamTestCore(useAsync: false); + return EventPipeSessionStreamTestCore(config, useAsync: false); } - [Fact] - public Task EventPipeSessionStreamTestAsync() + [SkippableTheory, MemberData(nameof(Configurations))] + public Task EventPipeSessionStreamTestAsync(TestConfiguration config) { - return EventPipeSessionStreamTestCore(useAsync: true); + return EventPipeSessionStreamTestCore(config, useAsync: true); } /// /// Checks if we can create an EventPipeSession and can get some expected events out of it. /// - private async Task EventPipeSessionStreamTestCore(bool useAsync) + private async Task EventPipeSessionStreamTestCore(TestConfiguration config, bool useAsync) { - TestRunner runner = new TestRunner(CommonHelper.GetTraceePathWithArgs(), output); - runner.Start(timeoutInMSPipeCreation: 15_000, testProcessTimeout: 60_000); + await using TestRunner runner = await TestRunner.Create(config, _output, "Tracee"); + await runner.Start(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}"); + runner.WriteLine($"Trying to start an EventPipe session"); using (var session = await clientShim.StartEventPipeSession(new List() { new EventPipeProvider("System.Runtime", EventLevel.Informational, 0, new Dictionary() { @@ -86,47 +89,46 @@ private async Task EventPipeSessionStreamTestCore(bool useAsync) Task streamTask = Task.Run(() => { var source = new EventPipeEventSource(session.EventStream); source.Dynamic.All += (TraceEvent obj) => { - output.WriteLine("Got an event"); + runner.WriteLine("Got an event"); evntCnt += 1; }; try { source.Process(); } - catch (Exception e) + catch (Exception ex) { // 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()); + runner.WriteLine($"Error encountered while processing events {ex}"); } finally { - runner.Stop(); + runner.WakeupTracee(); } }); - output.WriteLine("Waiting for stream Task"); + runner.WriteLine("Waiting for stream Task"); streamTask.Wait(10000); - output.WriteLine("Done waiting for stream Task"); + runner.WriteLine("Done waiting for stream Task"); Assert.True(evntCnt > 0); } } - [Fact] - public Task EventPipeSessionUnavailableTest() + [SkippableTheory, MemberData(nameof(Configurations))] + public Task EventPipeSessionUnavailableTest(TestConfiguration config) { - return EventPipeSessionUnavailableTestCore(useAsync: false); + return EventPipeSessionUnavailableTestCore(config, useAsync: false); } - [Fact] - public Task EventPipeSessionUnavailableTestAsync() + [SkippableTheory, MemberData(nameof(Configurations))] + public Task EventPipeSessionUnavailableTestAsync(TestConfiguration config) { - return EventPipeSessionUnavailableTestCore(useAsync: true); + return EventPipeSessionUnavailableTestCore(config, useAsync: true); } /// /// Tries to start an EventPipe session on a non-existent process /// - private async Task EventPipeSessionUnavailableTestCore(bool useAsync) + private async Task EventPipeSessionUnavailableTestCore(TestConfiguration config, bool useAsync) { List pids = new List(DiagnosticsClient.GetPublishedProcesses()); int arbitraryPid = 1; @@ -139,30 +141,29 @@ await Assert.ThrowsAsync(() => clientShim.StartEven })); } - [Fact] - public Task StartEventPipeSessionWithSingleProviderTest() + [SkippableTheory, MemberData(nameof(Configurations))] + public Task StartEventPipeSessionWithSingleProviderTest(TestConfiguration config) { - return StartEventPipeSessionWithSingleProviderTestCore(useAsync: false); + return StartEventPipeSessionWithSingleProviderTestCore(config, useAsync: false); } - [Fact] - public Task StartEventPipeSessionWithSingleProviderTestAsync() + [SkippableTheory, MemberData(nameof(Configurations))] + public Task StartEventPipeSessionWithSingleProviderTestAsync(TestConfiguration config) { - return StartEventPipeSessionWithSingleProviderTestCore(useAsync: true); + return StartEventPipeSessionWithSingleProviderTestCore(config, useAsync: true); } /// /// Test for the method overload: public EventPipeSession StartEventPipeSession(EventPipeProvider provider, bool requestRundown=true, int circularBufferMB=256) /// - private async Task StartEventPipeSessionWithSingleProviderTestCore(bool useAsync) + private async Task StartEventPipeSessionWithSingleProviderTestCore(TestConfiguration config, bool useAsync) { - using TestRunner runner = new TestRunner(CommonHelper.GetTraceePathWithArgs(), output); - runner.Start(timeoutInMSPipeCreation: 15_000, testProcessTimeout: 60_000); + await using TestRunner runner = await TestRunner.Create(config, _output, "Tracee"); + await runner.Start(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); - } + // Don't dispose of the session here because it unnecessarily hangs the test for 30 secs + EventPipeSession session = await clientShim.StartEventPipeSession(new EventPipeProvider("Microsoft-Windows-DotNETRuntime", EventLevel.Informational)); + Assert.True(session.EventStream != null); runner.Stop(); } } diff --git a/src/tests/Microsoft.Diagnostics.NETCore.Client/GetProcessEnvironmentTests.cs b/src/tests/Microsoft.Diagnostics.NETCore.Client/GetProcessEnvironmentTests.cs index 5a27f825fc..d191b42e20 100644 --- a/src/tests/Microsoft.Diagnostics.NETCore.Client/GetProcessEnvironmentTests.cs +++ b/src/tests/Microsoft.Diagnostics.NETCore.Client/GetProcessEnvironmentTests.cs @@ -2,53 +2,61 @@ // 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 Microsoft.Diagnostics.TestHelpers; using System.Collections.Generic; using System.Threading.Tasks; using Xunit; using Xunit.Abstractions; +using Xunit.Extensions; +using TestRunner = Microsoft.Diagnostics.CommonTestRunner.TestRunner; namespace Microsoft.Diagnostics.NETCore.Client { public class ProcessEnvironmentTests { - private readonly ITestOutputHelper output; + private readonly ITestOutputHelper _output; + + public static IEnumerable Configurations => TestRunner.Configurations; public ProcessEnvironmentTests(ITestOutputHelper outputHelper) { - output = outputHelper; + _output = outputHelper; } - [Fact] - public Task BasicEnvTest() + [SkippableTheory, MemberData(nameof(Configurations))] + public Task BasicEnvTest(TestConfiguration config) { - return BasicEnvTestCore(useAsync: false); + return BasicEnvTestCore(config, useAsync: false); } - [Fact] - public Task BasicEnvTestAsync() + [SkippableTheory, MemberData(nameof(Configurations))] + public Task BasicEnvTestAsync(TestConfiguration config) { - return BasicEnvTestCore(useAsync: true); + return BasicEnvTestCore(config, useAsync: true); } /// /// A simple test that collects process environment. /// - private async Task BasicEnvTestCore(bool useAsync) + private async Task BasicEnvTestCore(TestConfiguration config, bool useAsync) { + if (config.RuntimeFrameworkVersionMajor < 5) + { + throw new SkipTestException("Not supported on < .NET 5.0"); + } // 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); + await using TestRunner runner = await TestRunner.Create(config, _output, "Tracee"); string testKey = "FOO"; string testVal = "BAR"; runner.AddEnvVar(testKey, testVal); - runner.Start(timeoutInMSPipeCreation: 3000); + await runner.Start(); var clientShim = new DiagnosticsClientApiShim(new DiagnosticsClient(runner.Pid), useAsync); Dictionary env = await clientShim.GetProcessEnvironment(); Assert.True(env.ContainsKey(testKey) && env[testKey].Equals(testVal)); - runner.Stop(); + runner.WakeupTracee(); } } } diff --git a/src/tests/Microsoft.Diagnostics.NETCore.Client/GetProcessInfoTests.cs b/src/tests/Microsoft.Diagnostics.NETCore.Client/GetProcessInfoTests.cs index 53b514b1e4..2b986fabf8 100644 --- a/src/tests/Microsoft.Diagnostics.NETCore.Client/GetProcessInfoTests.cs +++ b/src/tests/Microsoft.Diagnostics.NETCore.Client/GetProcessInfoTests.cs @@ -2,10 +2,16 @@ // 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.CommonTestRunner; +using Microsoft.Diagnostics.TestHelpers; using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; using System.Threading.Tasks; using Xunit; using Xunit.Abstractions; +using Xunit.Extensions; +using TestRunner = Microsoft.Diagnostics.CommonTestRunner.TestRunner; namespace Microsoft.Diagnostics.NETCore.Client { @@ -13,43 +19,49 @@ public class GetProcessInfoTests { private readonly ITestOutputHelper _output; + public static IEnumerable Configurations => TestRunner.Configurations; + public GetProcessInfoTests(ITestOutputHelper outputHelper) { _output = outputHelper; } - [Fact] - public Task BasicProcessInfoNoSuspendTest() + [SkippableTheory, MemberData(nameof(Configurations))] + public Task BasicProcessInfoNoSuspendTest(TestConfiguration config) { - return BasicProcessInfoTestCore(useAsync: false, suspend: false); + return BasicProcessInfoTestCore(config, useAsync: false, suspend: false); } - [Fact] - public Task BasicProcessInfoNoSuspendTestAsync() + [SkippableTheory, MemberData(nameof(Configurations))] + public Task BasicProcessInfoNoSuspendTestAsync(TestConfiguration config) { - return BasicProcessInfoTestCore(useAsync: true, suspend: false); + return BasicProcessInfoTestCore(config, useAsync: true, suspend: false); } - [Fact] - public Task BasicProcessInfoSuspendTest() + [SkippableTheory, MemberData(nameof(Configurations))] + public Task BasicProcessInfoSuspendTest(TestConfiguration config) { - return BasicProcessInfoTestCore(useAsync: false, suspend: true); + return BasicProcessInfoTestCore(config, useAsync: false, suspend: true); } - [Fact] - public Task BasicProcessInfoSuspendTestAsync() + [SkippableTheory, MemberData(nameof(Configurations))] + public Task BasicProcessInfoSuspendTestAsync(TestConfiguration config) { - return BasicProcessInfoTestCore(useAsync: true, suspend: true); + return BasicProcessInfoTestCore(config, useAsync: true, suspend: true); } - private async Task BasicProcessInfoTestCore(bool useAsync, bool suspend) + private async Task BasicProcessInfoTestCore(TestConfiguration config, bool useAsync, bool suspend) { - using TestRunner runner = new TestRunner(CommonHelper.GetTraceePathWithArgs(targetFramework: "net5.0"), _output); + if (config.RuntimeFrameworkVersionMajor < 5) + { + throw new SkipTestException("Not supported on < .NET 5.0"); + } + await using TestRunner runner = await TestRunner.Create(config, _output, "Tracee"); if (suspend) { runner.SuspendDefaultDiagnosticPort(); } - runner.Start(); + await runner.Start(testProcessTimeout: 60_000, waitForTracee: !suspend); try { @@ -64,23 +76,36 @@ private async Task BasicProcessInfoTestCore(bool useAsync, bool suspend) Assert.True(string.IsNullOrEmpty(processInfoBeforeResume.ManagedEntrypointAssemblyName)); await clientShim.ResumeRuntime(); + + await runner.WaitForTracee(); } // 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); + + // This is only true if targetFramework for the tracee app is greater than 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); + // Given we are in a .NET 6.0+ app, we should have ProcessInfo2 available. Pre and post pause should differ. + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + Assert.Equal($"\"{runner.ExePath}\" {runner.Arguments}", processInfoBeforeResume.CommandLine); + Assert.Equal($"\"{runner.ExePath}\" {runner.Arguments}", processInfo.CommandLine); + } + else + { + Assert.Equal($"{runner.ExePath}", processInfoBeforeResume.CommandLine); + Assert.Equal($"{runner.ExePath} {runner.ManagedArguments}", processInfo.CommandLine); + } } } finally diff --git a/src/tests/Microsoft.Diagnostics.NETCore.Client/GetPublishedProcessesTests.cs b/src/tests/Microsoft.Diagnostics.NETCore.Client/GetPublishedProcessesTests.cs index 9f571b465e..ff77348124 100644 --- a/src/tests/Microsoft.Diagnostics.NETCore.Client/GetPublishedProcessesTests.cs +++ b/src/tests/Microsoft.Diagnostics.NETCore.Client/GetPublishedProcessesTests.cs @@ -2,6 +2,7 @@ // 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.TestHelpers; using System; using System.Collections.Generic; using System.Runtime.InteropServices; @@ -9,6 +10,8 @@ using System.Threading.Tasks; using Xunit; using Xunit.Abstractions; +using Xunit.Extensions; +using TestRunner = Microsoft.Diagnostics.CommonTestRunner.TestRunner; namespace Microsoft.Diagnostics.NETCore.Client { @@ -18,76 +21,75 @@ namespace Microsoft.Diagnostics.NETCore.Client /// public class GetPublishedProcessesTest { - private readonly ITestOutputHelper output; + private readonly ITestOutputHelper _output; + + public static IEnumerable Configurations => TestRunner.Configurations; public GetPublishedProcessesTest(ITestOutputHelper outputHelper) { - output = outputHelper; + _output = outputHelper; } - [Fact] - public void PublishedProcessTest1() + [SkippableTheory, MemberData(nameof(Configurations))] + public async Task PublishedProcessTest1(TestConfiguration config) { - using TestRunner runner = new TestRunner(CommonHelper.GetTraceePathWithArgs(), output); - runner.Start(timeoutInMSPipeCreation: 3000); - // On Windows, runner.Start will not wait for named pipe creation since for other tests, NamedPipeClientStream will - // just wait until the named pipe is created. - // For these tests, we need to sleep an arbitrary time before pipe is created. - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - Thread.Sleep(5000); - } + await using TestRunner runner = await TestRunner.Create(config, _output, "Tracee"); + await runner.Start(); + List publishedProcesses = new List(DiagnosticsClient.GetPublishedProcesses()); foreach (int p in publishedProcesses) { - output.WriteLine($"[{DateTime.Now.ToString()}] Saw published process {p}"); + runner.WriteLine($"Saw published process {p}"); } Assert.Contains(publishedProcesses, p => p == runner.Pid); - runner.Stop(); + runner.WakeupTracee(); } - [Fact] - public void MultiplePublishedProcessTest() + [SkippableTheory, MemberData(nameof(Configurations))] + public async Task MultiplePublishedProcessTest(TestConfiguration config) { TestRunner[] runner = new TestRunner[3]; int[] pids = new int[3]; - for (var i = 0; i < 3; i++) - { - runner[i] = new TestRunner(CommonHelper.GetTraceePathWithArgs(), output); - runner[i].Start(); - pids[i] = runner[i].Pid; - } - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - Thread.Sleep(5000); - } - List publishedProcesses = new List(DiagnosticsClient.GetPublishedProcesses()); - foreach (int p in publishedProcesses) + try { - output.WriteLine($"[{DateTime.Now.ToString()}] Saw published process {p}"); - } + for (var i = 0; i < 3; i++) + { + runner[i] = await TestRunner.Create(config, _output, "Tracee"); + await runner[i].Start(); + pids[i] = runner[i].Pid; + } - for (var i = 0; i < 3; i++) - { - Assert.Contains(publishedProcesses, p => p == pids[i]); - } + List publishedProcesses = new List(DiagnosticsClient.GetPublishedProcesses()); + foreach (int p in publishedProcesses) + { + _output.WriteLine($"[{DateTime.Now}] Saw published process {p}"); + } + + for (var i = 0; i < 3; i++) + { + Assert.Contains(publishedProcesses, p => p == pids[i]); + } - for (var i = 0 ; i < 3; i++) + for (var i = 0; i < 3; i++) + { + runner[i].WakeupTracee(); + } + } + finally { - runner[i].Stop(); + for (var i = 0; i < 3; i++) + { + await runner[i].DisposeAsync(); + } } } - [Fact] - public async Task WaitForConnectionTest() + [SkippableTheory, MemberData(nameof(Configurations))] + public async Task WaitForConnectionTest(TestConfiguration config) { - using TestRunner runner = new TestRunner(CommonHelper.GetTraceePathWithArgs(), output); - runner.Start(timeoutInMSPipeCreation: 3000); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - Thread.Sleep(5000); - } + await using TestRunner runner = await TestRunner.Create(config, _output, "Tracee"); + await runner.Start(); var client = new DiagnosticsClient(runner.Pid); using var timeoutSource = new CancellationTokenSource(TimeSpan.FromMilliseconds(250)); @@ -97,7 +99,7 @@ public async Task WaitForConnectionTest() } finally { - runner.Stop(); + runner.WakeupTracee(); } } } diff --git a/src/tests/Microsoft.Diagnostics.NETCore.Client/Microsoft.Diagnostics.NETCore.Client.UnitTests.csproj b/src/tests/Microsoft.Diagnostics.NETCore.Client/Microsoft.Diagnostics.NETCore.Client.UnitTests.csproj index b1c14ebee1..8db5cfa78f 100644 --- a/src/tests/Microsoft.Diagnostics.NETCore.Client/Microsoft.Diagnostics.NETCore.Client.UnitTests.csproj +++ b/src/tests/Microsoft.Diagnostics.NETCore.Client/Microsoft.Diagnostics.NETCore.Client.UnitTests.csproj @@ -1,66 +1,17 @@  - - - - $(IntermediateOutputPath)/DARCVersion.g.cs - - - - - - - - - - - - - - - - - - - - netcoreapp3.1;net5.0 + $(UnitTestTargetFrameworks) - - - + + + + - - - - + diff --git a/src/tests/Microsoft.Diagnostics.NETCore.Client/RemoteTestExecution.cs b/src/tests/Microsoft.Diagnostics.NETCore.Client/RemoteTestExecution.cs deleted file mode 100644 index a3b592339d..0000000000 --- a/src/tests/Microsoft.Diagnostics.NETCore.Client/RemoteTestExecution.cs +++ /dev/null @@ -1,110 +0,0 @@ -// 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.IO; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Diagnostics.NETCore.Client; -using Xunit.Abstractions; - -namespace Microsoft.Diagnostics.NETCore.Client.UnitTests -{ - /// - /// Utility class to control remote test execution. - /// - public sealed class RemoteTestExecution : IAsyncDisposable - { - private Task IoReadingTask { get; } - - private ITestOutputHelper OutputHelper { get; } - - public TestRunner TestRunner { get; } - - private RemoteTestExecution(TestRunner runner, Task ioReadingTask, ITestOutputHelper outputHelper) - { - TestRunner = runner; - IoReadingTask = ioReadingTask; - OutputHelper = outputHelper; - } - - //Very simple signals that synchronize execution between the test process and the debuggee process. - - public void SendSignal() - { - //We cannot use named synchronization primitives since they do not work across processes - //on Linux. Use redirected standard input instead. - TestRunner.StandardInput.Write('0'); - TestRunner.StandardInput.Flush(); - } - - public void WaitForSignal() - { - var result = TestRunner.StandardOutput.ReadLine(); - if (string.Equals(result, "1")) - { - return; - } - } - - public static RemoteTestExecution StartProcess(string commandLine, ITestOutputHelper outputHelper, string reversedServerTransportName = null) - { - TestRunner runner = new TestRunner(commandLine, outputHelper, redirectError: true, redirectInput: true); - if (!string.IsNullOrEmpty(reversedServerTransportName)) - { - runner.SetDiagnosticPort(reversedServerTransportName, suspend: false); - } - runner.Start(testProcessTimeout: 60_000); - - Task readingTask = ReadAllOutput(runner.StandardOutput, runner.StandardError, outputHelper); - - return new RemoteTestExecution(runner, readingTask, outputHelper); - } - - private static Task ReadAllOutput(StreamReader output, StreamReader error, ITestOutputHelper outputHelper) - { - return Task.Run(async () => - { - try - { - Task stdErrorTask = error.ReadToEndAsync(); - - try - { - string result = await stdErrorTask; - outputHelper.WriteLine("Stderr:"); - if (result != null) - { - outputHelper.WriteLine(result); - } - } - catch (Exception e) - { - outputHelper.WriteLine("Error reading standard error from child process: " + e.ToString()); - } - } - catch (ObjectDisposedException) - { - outputHelper.WriteLine("Failed to collect remote process's output"); - } - }); - } - - public async ValueTask DisposeAsync() - { - using var timeoutSource = new CancellationTokenSource(TimeSpan.FromSeconds(1)); - try - { - await TestRunner.WaitForExitAsync(timeoutSource.Token); - } - catch (OperationCanceledException) - { - OutputHelper.WriteLine("Remote process did not exit within timeout period. Forcefully stopping process."); - TestRunner.Stop(); - } - - await IoReadingTask; - } - } -} diff --git a/src/tests/Microsoft.Diagnostics.NETCore.Client/ReversedServerTests.cs b/src/tests/Microsoft.Diagnostics.NETCore.Client/ReversedServerTests.cs index 07f6a17170..e7a1867f1c 100644 --- a/src/tests/Microsoft.Diagnostics.NETCore.Client/ReversedServerTests.cs +++ b/src/tests/Microsoft.Diagnostics.NETCore.Client/ReversedServerTests.cs @@ -2,6 +2,9 @@ // 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.CommonTestRunner; +using Microsoft.Diagnostics.TestHelpers; +using Microsoft.Diagnostics.Tracing; using System; using System.Collections.Generic; using System.Diagnostics.Tracing; @@ -9,9 +12,10 @@ using System.Net; using System.Threading; using System.Threading.Tasks; -using Microsoft.Diagnostics.Tracing; using Xunit; using Xunit.Abstractions; +using Xunit.Extensions; +using TestRunner = Microsoft.Diagnostics.CommonTestRunner.TestRunner; namespace Microsoft.Diagnostics.NETCore.Client { @@ -23,6 +27,8 @@ public class ReversedServerTests private readonly ITestOutputHelper _outputHelper; + public static IEnumerable Configurations => TestRunner.Configurations; + public ReversedServerTests(ITestOutputHelper outputHelper) { _outputHelper = outputHelper; @@ -111,22 +117,22 @@ public async Task ReversedServerAcceptAsyncYieldsTest() Assert.True(acceptTask.IsCanceled); } - [Fact] - public async Task ReversedServerNonExistingRuntimeIdentifierTest() + [SkippableTheory, MemberData(nameof(Configurations))] + public async Task ReversedServerNonExistingRuntimeIdentifierTest(TestConfiguration config) { - await ReversedServerNonExistingRuntimeIdentifierTestCore(useAsync: false); + await ReversedServerNonExistingRuntimeIdentifierTestCore(config, useAsync: false); } - [Fact] - public async Task ReversedServerNonExistingRuntimeIdentifierTestAsync() + [SkippableTheory, MemberData(nameof(Configurations))] + public async Task ReversedServerNonExistingRuntimeIdentifierTestAsync(TestConfiguration config) { - await ReversedServerNonExistingRuntimeIdentifierTestCore(useAsync: true); + await ReversedServerNonExistingRuntimeIdentifierTestCore(config, useAsync: true); } /// /// Tests that invoking server methods with non-existing runtime identifier appropriately fail. /// - private async Task ReversedServerNonExistingRuntimeIdentifierTestCore(bool useAsync) + private async Task ReversedServerNonExistingRuntimeIdentifierTestCore(TestConfiguration config, bool useAsync) { await using var server = CreateReversedServer(out string transportName); @@ -149,16 +155,16 @@ private async Task ReversedServerNonExistingRuntimeIdentifierTestCore(bool useAs Assert.False(server.RemoveConnection(Guid.NewGuid()), "Removal of nonexisting connection should fail."); } - [Fact] - public async Task ReversedServerSingleTargetMultipleUseClientTest() + [SkippableTheory, MemberData(nameof(Configurations))] + public async Task ReversedServerSingleTargetMultipleUseClientTest(TestConfiguration config) { - await ReversedServerSingleTargetMultipleUseClientTestCore(useAsync: false); + await ReversedServerSingleTargetMultipleUseClientTestCore(config, useAsync: false); } - [Fact] - public async Task ReversedServerSingleTargetMultipleUseClientTestAsync() + [SkippableTheory, MemberData(nameof(Configurations))] + public async Task ReversedServerSingleTargetMultipleUseClientTestAsync(TestConfiguration config) { - await ReversedServerSingleTargetMultipleUseClientTestCore(useAsync: true); + await ReversedServerSingleTargetMultipleUseClientTestCore(config, useAsync: true); } /// @@ -170,18 +176,19 @@ public async Task ReversedServerSingleTargetMultipleUseClientTestAsync() /// because of how the endpoint is updated with new stream information each /// time the target process reconnects to the server. /// - private async Task ReversedServerSingleTargetMultipleUseClientTestCore(bool useAsync) + private async Task ReversedServerSingleTargetMultipleUseClientTestCore(TestConfiguration config, bool useAsync) { + if (config.RuntimeFrameworkVersionMajor < 5) + { + throw new SkipTestException("Not supported on < .NET 5.0"); + } await using var server = CreateReversedServer(out string transportName); server.Start(); - - TestRunner runner = null; IpcEndpointInfo info; - try - { - // Start client pointing to diagnostics server - runner = StartTracee(transportName); + // Start client pointing to diagnostics server + await using (TestRunner runner = await StartTracee(config, transportName)) + { info = await AcceptEndpointInfo(server, useAsync); await VerifyEndpointInfo(runner, info, useAsync); @@ -191,13 +198,10 @@ private async Task ReversedServerSingleTargetMultipleUseClientTestCore(bool useA await ResumeRuntime(info, useAsync); + await runner.WaitForTracee(); + await VerifySingleSession(info, useAsync); } - finally - { - _outputHelper.WriteLine("Stopping tracee."); - runner?.Stop(); - } // Wait some time for the process to exit await Task.Delay(TimeSpan.FromSeconds(1)); @@ -211,33 +215,34 @@ private async Task ReversedServerSingleTargetMultipleUseClientTestCore(bool useA await VerifyNoNewEndpointInfos(server, useAsync); } - [Fact] - public async Task ReversedServerSingleTargetExitsClientInviableTest() + [SkippableTheory, MemberData(nameof(Configurations))] + public async Task ReversedServerSingleTargetExitsClientInviableTest(TestConfiguration config) { - await ReversedServerSingleTargetExitsClientInviableTestCore(useAsync: false); + await ReversedServerSingleTargetExitsClientInviableTestCore(config, useAsync: false); } - [Fact] - public async Task ReversedServerSingleTargetExitsClientInviableTestAsync() + [SkippableTheory, MemberData(nameof(Configurations))] + public async Task ReversedServerSingleTargetExitsClientInviableTestAsync(TestConfiguration config) { - await ReversedServerSingleTargetExitsClientInviableTestCore(useAsync: true); + await ReversedServerSingleTargetExitsClientInviableTestCore(config, useAsync: true); } /// /// Tests that a DiagnosticsClient is not viable after target exists. /// - private async Task ReversedServerSingleTargetExitsClientInviableTestCore(bool useAsync) + private async Task ReversedServerSingleTargetExitsClientInviableTestCore(TestConfiguration config, bool useAsync) { + if (config.RuntimeFrameworkVersionMajor < 5) + { + throw new SkipTestException("Not supported on < .NET 5.0"); + } await using var server = CreateReversedServer(out string transportName); server.Start(); - TestRunner runner = null; + // Start client pointing to diagnostics server IpcEndpointInfo info; - try + await using (TestRunner runner = await StartTracee(config, transportName)) { - // Start client pointing to diagnostics server - runner = StartTracee(transportName); - // Get client connection info = await AcceptEndpointInfo(server, useAsync); @@ -248,13 +253,10 @@ private async Task ReversedServerSingleTargetExitsClientInviableTestCore(bool us await ResumeRuntime(info, useAsync); + await runner.WaitForTracee(); + await VerifyWaitForConnection(info, useAsync); } - finally - { - _outputHelper.WriteLine("Stopping tracee."); - runner?.Stop(); - } // Wait some time for the process to exit await Task.Delay(TimeSpan.FromSeconds(1)); @@ -272,22 +274,22 @@ private async Task ReversedServerSingleTargetExitsClientInviableTestCore(bool us /// Validates that the does not create a new server /// transport during disposal. /// - [Fact] - public async Task ReversedServerNoCreateTransportAfterDispose() + [SkippableTheory, MemberData(nameof(Configurations))] + public async Task ReversedServerNoCreateTransportAfterDispose(TestConfiguration config) { + if (config.RuntimeFrameworkVersionMajor < 5) + { + throw new SkipTestException("Not supported on < .NET 5.0"); + } var transportCallback = new IpcServerTransportCallback(); - int transportVersion = 0; - TestRunner runner = null; - try - { - await using var server = CreateReversedServer(out string transportName); - server.TransportCallback = transportCallback; - server.Start(); - // Start client pointing to diagnostics server - runner = StartTracee(transportName); + await using var server = CreateReversedServer(out string transportName); + server.TransportCallback = transportCallback; + server.Start(); + await using (TestRunner runner = await StartTracee(config, transportName)) + { // Get client connection IpcEndpointInfo info = await AcceptEndpointInfo(server, useAsync: true); @@ -298,17 +300,14 @@ public async Task ReversedServerNoCreateTransportAfterDispose() await ResumeRuntime(info, useAsync: true); + await runner.WaitForTracee(); + await VerifyWaitForConnection(info, useAsync: true); transportVersion = await transportCallback.GetStableTransportVersion(); // Server will be disposed } - finally - { - _outputHelper.WriteLine("Stopping tracee."); - runner?.Stop(); - } // Check that the reversed server did not create a new server transport upon disposal. Assert.Equal(transportVersion, await transportCallback.GetStableTransportVersion()); @@ -328,12 +327,11 @@ private async Task AcceptEndpointInfo(ReversedDiagnosticsServer return await shim.Accept(DefaultPositiveVerificationTimeout); } - private TestRunner StartTracee(string transportName) + private async Task StartTracee(TestConfiguration config, string transportName) { - _outputHelper.WriteLine("Starting tracee."); - var runner = new TestRunner(CommonHelper.GetTraceePathWithArgs(targetFramework: "net5.0"), _outputHelper); + TestRunner runner = await TestRunner.Create(config, _outputHelper, "Tracee"); runner.SetDiagnosticPort(transportName, suspend: true); - runner.Start(); + await runner.Start(waitForTracee: false); return runner; } @@ -364,7 +362,7 @@ private async Task VerifyNoNewEndpointInfos(ReversedDiagnosticsServer server, bo /// private async Task VerifyEndpointInfo(TestRunner runner, IpcEndpointInfo info, bool useAsync, bool expectTimeout = false) { - _outputHelper.WriteLine($"Verifying connection information for process ID {runner.Pid}."); + runner.WriteLine("Verifying connection information for process"); Assert.NotNull(runner); Assert.Equal(runner.Pid, info.ProcessId); Assert.NotEqual(Guid.Empty, info.RuntimeInstanceCookie); @@ -372,7 +370,7 @@ private async Task VerifyEndpointInfo(TestRunner runner, IpcEndpointInfo info, b await VerifyWaitForConnection(info, useAsync, expectTimeout); - _outputHelper.WriteLine($"Connection: {info.DebuggerDisplay}"); + runner.WriteLine($"Connection: {info.DebuggerDisplay}"); } private async Task ResumeRuntime(IpcEndpointInfo info, bool useAsync) diff --git a/src/tests/Microsoft.Diagnostics.NETCore.Client/TestRunner.cs b/src/tests/Microsoft.Diagnostics.NETCore.Client/TestRunner.cs deleted file mode 100644 index 88fa0014ee..0000000000 --- a/src/tests/Microsoft.Diagnostics.NETCore.Client/TestRunner.cs +++ /dev/null @@ -1,178 +0,0 @@ -// 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.Linq; -using System.ComponentModel; -using System.Diagnostics; -using System.IO; -using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; -using Xunit.Abstractions; -using System.Collections.Generic; - -namespace Microsoft.Diagnostics.NETCore.Client -{ - public class TestRunner : IDisposable - { - private Process testProcess; - private ProcessStartInfo startInfo; - private ITestOutputHelper outputHelper; - private CancellationTokenSource cts; - - public TestRunner(string testExePath, ITestOutputHelper _outputHelper = null, - bool redirectError = false, bool redirectInput = false, Dictionary envVars = null) - { - startInfo = new ProcessStartInfo(CommonHelper.HostExe, testExePath); - startInfo.UseShellExecute = false; - startInfo.RedirectStandardOutput = true; - startInfo.RedirectStandardError = redirectError; - startInfo.RedirectStandardInput = redirectInput; - envVars?.ToList().ForEach(item => startInfo.Environment.Add(item.Key, item.Value)); - outputHelper = _outputHelper; - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - try - { - // Make a good will attempt to end the tracee process - // and its process tree - testProcess?.Kill(entireProcessTree: true); - } - catch {} - - if(disposing) - { - testProcess?.Dispose(); - } - - cts.Dispose(); - } - - public void AddEnvVar(string key, string value) - { - startInfo.EnvironmentVariables[key] = value; - } - - public StreamWriter StandardInput => testProcess.StandardInput; - public StreamReader StandardOutput => testProcess.StandardOutput; - public StreamReader StandardError => testProcess.StandardError; - - public void Start(int timeoutInMSPipeCreation=15_000, int testProcessTimeout=30_000) - { - if (outputHelper != null) - outputHelper.WriteLine($"[{DateTime.Now.ToString()}] Launching test: " + startInfo.FileName + " " + startInfo.Arguments); - - testProcess = new Process(); - testProcess.StartInfo = startInfo; - testProcess.EnableRaisingEvents = true; - - if (!testProcess.Start()) - { - outputHelper.WriteLine($"Could not start process: " + startInfo.FileName); - } - - if (testProcess.HasExited) - { - outputHelper.WriteLine($"Process " + startInfo.FileName + " came back as exited"); - } - - cts = new CancellationTokenSource(testProcessTimeout); - cts.Token.Register(() => testProcess.Kill()); - - if (outputHelper != null) - { - outputHelper.WriteLine($"[{DateTime.Now.ToString()}] Successfully started process {testProcess.Id}"); - // Retry getting the module count because we can catch the process during startup and it fails temporarily. - for (int retry = 0; retry < 5; retry++) - { - try - { - outputHelper.WriteLine($"Have total {testProcess.Modules.Count} modules loaded"); - break; - } - catch (Win32Exception) - { - } - } - } - - // Block until we see the IPC channel created, or until timeout specified. - Task monitorSocketTask = Task.Run(() => - { - while (true) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - // On Windows, named pipe connection will block until the named pipe is ready to connect so no need to block here - break; - } - else - { - // On Linux, we wait until the socket is created. - var matchingFiles = Directory.GetFiles(Path.GetTempPath(), $"dotnet-diagnostic-{testProcess.Id}-*-socket"); // Try best match. - if (matchingFiles.Length > 0) - { - break; - } - } - Task.Delay(100); - } - }); - - monitorSocketTask.Wait(TimeSpan.FromMilliseconds(timeoutInMSPipeCreation)); - } - - public void Stop() - { - this.Dispose(); - } - - public int Pid { - get { return testProcess.Id; } - } - - public void PrintStatus() - { - if (testProcess.HasExited) - { - outputHelper.WriteLine($"Process {testProcess.Id} status: Exited 0x{testProcess.ExitCode:X}"); - } - else - { - outputHelper.WriteLine($"Process {testProcess.Id} status: Running"); - } - } - - public async Task WaitForExitAsync(CancellationToken token) - { - TaskCompletionSource exitedSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - EventHandler exitedHandler = (s, e) => exitedSource.TrySetResult(null); - - testProcess.Exited += exitedHandler; - try - { - if (!testProcess.HasExited) - { - using var _ = token.Register(() => exitedSource.TrySetCanceled(token)); - - await exitedSource.Task; - } - } - finally - { - testProcess.Exited -= exitedHandler; - } - } - } -} diff --git a/src/tests/StackTracee/Program.cs b/src/tests/StackTracee/Program.cs index 12dc739197..efbd514851 100644 --- a/src/tests/StackTracee/Program.cs +++ b/src/tests/StackTracee/Program.cs @@ -10,7 +10,7 @@ class Program { static void Main(string[] args) { - Console.ReadKey(); + Console.Read(); } } } diff --git a/src/tests/StackTracee/StackTracee.csproj b/src/tests/StackTracee/StackTracee.csproj index cd0510ad22..6b634ef181 100644 --- a/src/tests/StackTracee/StackTracee.csproj +++ b/src/tests/StackTracee/StackTracee.csproj @@ -2,6 +2,6 @@ Exe $(BuildProjectFramework) - netcoreapp3.1;net5.0 + netcoreapp3.1;net6.0;net7.0 diff --git a/src/tests/Tracee/Program.cs b/src/tests/Tracee/Program.cs index 8250ea7c8e..2107a7f9fa 100644 --- a/src/tests/Tracee/Program.cs +++ b/src/tests/Tracee/Program.cs @@ -3,27 +3,50 @@ // See the LICENSE file in the project root for more information. using System; -using System.Threading; +using System.Diagnostics; +using System.IO.Pipes; namespace Tracee { class Program { - private const int LoopCount = 30; - - static void Main(string[] args) + public static int Main(string[] args) { - Console.WriteLine("Sleep in loop for {0} seconds.", LoopCount); - - // Runs for max of 30 sec - for (var i = 0; i < LoopCount; i++) + int pid = Process.GetCurrentProcess().Id; + string pipeServerName = args.Length > 0 ? args[0] : null; + if (pipeServerName == null) { - Console.WriteLine("Iteration #{0}", i); - Thread.Sleep(1000); + Console.Error.WriteLine($"{pid} Tracee: no pipe name"); + Console.Error.Flush(); + return -1; } + Console.WriteLine($"{pid} Tracee: pipe server: {pipeServerName}"); + Console.Out.Flush(); + try + { + using var pipeStream = new NamedPipeClientStream(pipeServerName); + + Console.WriteLine("{0} Tracee: connecting to pipe", pid); + Console.Out.Flush(); + pipeStream.Connect(5 * 60 * 1000); + Console.WriteLine("{0} Tracee: connected to pipe", pid); + Console.Out.Flush(); - Console.WriteLine("Press any key to exit."); - Console.ReadKey(); + // Wait for server to send something + int input = pipeStream.ReadByte(); + + Console.WriteLine("{0} Tracee: waking up {1}", pid, input); + Console.Out.Flush(); + } + catch (Exception ex) + { + Console.Error.WriteLine(ex.ToString()); + Console.Error.Flush(); + return -1; + } + Console.WriteLine("{0} Tracee: exiting normally", pid); + Console.Out.Flush(); + return 0; } } } diff --git a/src/tests/Tracee/Tracee.csproj b/src/tests/Tracee/Tracee.csproj index cd0510ad22..6b634ef181 100644 --- a/src/tests/Tracee/Tracee.csproj +++ b/src/tests/Tracee/Tracee.csproj @@ -2,6 +2,6 @@ Exe $(BuildProjectFramework) - netcoreapp3.1;net5.0 + netcoreapp3.1;net6.0;net7.0 diff --git a/src/tests/dotnet-counters/DotnetCounters.UnitTests.csproj b/src/tests/dotnet-counters/DotnetCounters.UnitTests.csproj index 3e891e2a45..06c1878141 100644 --- a/src/tests/dotnet-counters/DotnetCounters.UnitTests.csproj +++ b/src/tests/dotnet-counters/DotnetCounters.UnitTests.csproj @@ -1,7 +1,7 @@ - net5.0 + net6.0 diff --git a/src/tests/dotnet-stack/DotnetStack.UnitTests.csproj b/src/tests/dotnet-stack/DotnetStack.UnitTests.csproj index 94b587a2ec..7cdad15afc 100644 --- a/src/tests/dotnet-stack/DotnetStack.UnitTests.csproj +++ b/src/tests/dotnet-stack/DotnetStack.UnitTests.csproj @@ -1,12 +1,12 @@ - net5.0 + net6.0 - - + + diff --git a/src/tests/dotnet-stack/StackTests.cs b/src/tests/dotnet-stack/StackTests.cs index e98820c08e..c106d1e366 100644 --- a/src/tests/dotnet-stack/StackTests.cs +++ b/src/tests/dotnet-stack/StackTests.cs @@ -2,45 +2,71 @@ // 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.NETCore.Client; +using Microsoft.Diagnostics.TestHelpers; using System; +using System.Collections.Generic; using System.CommandLine; using System.CommandLine.IO; using System.CommandLine.Parsing; using System.Threading.Tasks; using Xunit; using Xunit.Abstractions; +using Xunit.Extensions; +using TestRunner = Microsoft.Diagnostics.CommonTestRunner.TestRunner; namespace Microsoft.Diagnostics.Tools.Stack { public class StackTests { - private readonly ITestOutputHelper output; + private readonly ITestOutputHelper _output; + + private const string _correctStack70 = @" [Native Frames] + System.Console.il!Interop+Kernel32.ReadFile(int,unsigned int8*,int32,int32&,int) + System.Console.il!System.ConsolePal+WindowsConsoleStream.ReadFileNative(int,value class System.Span`1,bool,int32&,bool) + System.Console.il!System.ConsolePal+WindowsConsoleStream.Read(value class System.Span`1) + System.Console.il!System.IO.ConsoleStream.Read(unsigned int8[],int32,int32) + System.Private.CoreLib.il!System.IO.StreamReader.ReadBuffer() + System.Private.CoreLib.il!System.IO.StreamReader.Read() + System.Console.il!System.IO.SyncTextReader.Read() + System.Console.il!System.Console.Read() + ?!?"; + + private const string _correctStack60 = @" [Native Frames] + System.Console.il!System.ConsolePal+WindowsConsoleStream.ReadFileNative(int,value class System.Span`1,bool,int32&,bool) + System.Console.il!System.ConsolePal+WindowsConsoleStream.Read(value class System.Span`1) + System.Console.il!System.IO.ConsoleStream.Read(unsigned int8[],int32,int32) + System.Private.CoreLib.il!System.IO.StreamReader.ReadBuffer() + System.Private.CoreLib.il!System.IO.StreamReader.Read() + System.Console.il!System.IO.SyncTextReader.Read() + System.Console.il!System.Console.Read() + StackTracee!Tracee.Program.Main(class System.String[])"; - private readonly string correctStack = @" [Native Frames] - System.Console!System.IO.StdInReader.ReadKey(bool&) - System.Console!System.IO.SyncTextReader.ReadKey(bool&) - System.Console!System.ConsolePal.ReadKey(bool) - System.Console!System.Console.ReadKey() + private const string _correctStack31 = @" [Native Frames] + System.Console.il!System.ConsolePal+WindowsConsoleStream.ReadFileNative(int,unsigned int8[],int32,int32,bool,int32&,bool) + System.Console.il!System.ConsolePal+WindowsConsoleStream.Read(unsigned int8[],int32,int32) + System.Private.CoreLib.il!System.IO.StreamReader.ReadBuffer() + System.Private.CoreLib.il!System.IO.StreamReader.Read() + System.Console.il!System.IO.SyncTextReader.Read() + System.Console.il!System.Console.Read() StackTracee!Tracee.Program.Main(class System.String[])"; + public static IEnumerable Configurations => TestRunner.Configurations; + public StackTests(ITestOutputHelper outputHelper) { - output = outputHelper; + _output = outputHelper; } - [Theory] - [InlineData("netcoreapp3.1")] - [InlineData("net5.0")] - public async Task ReportsStacksCorrectly(string traceeFramework) + [SkippableTheory, MemberData(nameof(Configurations))] + public async Task ReportsStacksCorrectly(TestConfiguration config) { Command reportCommand = ReportCommandHandler.ReportCommand(); var console = new TestConsole(); var parser = new Parser(reportCommand); - using TestRunner runner = new TestRunner(CommonHelper.GetTraceePathWithArgs(traceeName: "StackTracee", targetFramework: traceeFramework), output); - runner.Start(); + await using TestRunner runner = await TestRunner.Create(config, _output, "StackTracee", usePipe: false); + await runner.Start(); // Wait for tracee to get to readkey call await Task.Delay(TimeSpan.FromSeconds(1)); @@ -49,10 +75,16 @@ public async Task ReportsStacksCorrectly(string traceeFramework) string report = console.Out.ToString(); - output.WriteLine($"REPORT_START\n{report}REPORT_END"); + runner.WriteLine($"REPORT_START\n{report}REPORT_END"); Assert.True(!string.IsNullOrEmpty(report)); - + string correctStack = config.RuntimeFrameworkVersionMajor switch + { + 7 => _correctStack70, + 6 => _correctStack60, + 3 => _correctStack31, + _ => throw new NotSupportedException($"Runtime version {config.RuntimeFrameworkVersionMajor} not supported") + }; string[] correctStackParts = correctStack.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries); string[] stackParts = report.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries); @@ -68,4 +100,4 @@ public async Task ReportsStacksCorrectly(string traceeFramework) } } } -} \ No newline at end of file +} diff --git a/src/tests/dotnet-trace/ChildProcessTests.cs b/src/tests/dotnet-trace/ChildProcessTests.cs index 14101e28c9..35a003046f 100644 --- a/src/tests/dotnet-trace/ChildProcessTests.cs +++ b/src/tests/dotnet-trace/ChildProcessTests.cs @@ -2,19 +2,23 @@ // 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.NETCore.Client; -using System; -using Xunit; -using Xunit.Abstractions; +using Microsoft.Diagnostics.CommonTestRunner; +using Microsoft.Diagnostics.TestHelpers; using System.Collections.Generic; -using System.Linq; using System.Diagnostics; +using System.Text; +using Xunit; +using Xunit.Abstractions; +using Xunit.Extensions; +using TestRunner = Microsoft.Diagnostics.CommonTestRunner.TestRunner; namespace Microsoft.Diagnostics.Tools.Trace { public class ChildProcessTests { + public static IEnumerable Configurations => TestRunner.Configurations; + // Pass ITestOutputHelper into the test class, which xunit provides per-test public ChildProcessTests(ITestOutputHelper outputHelper) { @@ -23,10 +27,35 @@ public ChildProcessTests(ITestOutputHelper outputHelper) private ITestOutputHelper OutputHelper { get; } - private void LaunchDotNetTrace(string command, out int exitCode, out string stdOut, out string stdErr) + private void LaunchDotNetTrace(TestConfiguration config, string dotnetTraceCommand, string traceeArguments, out int exitCode, out string stdOut, out string stdErr) { - string dotnetTracePathWithArgs = CommonHelper.GetTraceePathWithArgs(traceeName: "dotnet-trace").Replace("net5.0", "netcoreapp3.1"); - ProcessStartInfo startInfo = new ProcessStartInfo(CommonHelper.HostExe, $"{dotnetTracePathWithArgs} {command}"); + if (config.RuntimeFrameworkVersionMajor < 5) + { + throw new SkipTestException("Not supported on < .NET 5.0"); + } + DebuggeeConfiguration debuggeeConfig = DebuggeeCompiler.Execute(config, "ExitCodeTracee", OutputHelper).GetAwaiter().GetResult(); + + var dotnetTraceArguments = new StringBuilder(); + dotnetTraceArguments.Append(config.DotNetTracePath()); + dotnetTraceArguments.Append(' '); + dotnetTraceArguments.Append(dotnetTraceCommand); + dotnetTraceArguments.Append(" -- "); + + if (!string.IsNullOrWhiteSpace(config.HostExe)) + { + dotnetTraceArguments.Append(config.HostExe); + dotnetTraceArguments.Append(' '); + if (!string.IsNullOrWhiteSpace(config.HostArgs)) + { + dotnetTraceArguments.Append(config.HostArgs); + dotnetTraceArguments.Append(' '); + } + } + dotnetTraceArguments.Append(debuggeeConfig.BinaryExePath); + dotnetTraceArguments.Append(' '); + dotnetTraceArguments.Append(traceeArguments); + + ProcessStartInfo startInfo = new ProcessStartInfo(config.DotNetTraceHost(), dotnetTraceArguments.ToString()); OutputHelper.WriteLine($"Launching: {startInfo.FileName} {startInfo.Arguments}"); startInfo.RedirectStandardInput = true; @@ -53,45 +82,47 @@ private void LaunchDotNetTrace(string command, out int exitCode, out string stdO Assert.True(processExitedCleanly, "Launched process failed to exit"); exitCode = process.ExitCode; } + + if (!string.IsNullOrWhiteSpace(stdErr)) + { + OutputHelper.WriteLine(stdErr); + } } - [Theory] - [InlineData("232", 232)] - [InlineData("0", 0)] - public void VerifyExitCode(string commandLineArg, int exitCode) + [SkippableTheory, MemberData(nameof(Configurations))] + public void VerifyExitCode(TestConfiguration config) { - string exitCodeTraceePath = CommonHelper.GetTraceePathWithArgs(traceeName: "ExitCodeTracee", targetFramework: "net5.0"); + VerifyExitCodeX(config, "232", 232); + VerifyExitCodeX(config, "0", 0); + } - LaunchDotNetTrace($"collect -o verifyexitcode.nettrace -- {CommonHelper.HostExe} {exitCodeTraceePath} {commandLineArg}", out int dotnetTraceExitCode, out string stdOut, out string stdErr); + private void VerifyExitCodeX(TestConfiguration config, string commandLineArg, int exitCode) + { + LaunchDotNetTrace(config, "collect -o verifyexitcode.nettrace", commandLineArg, out int dotnetTraceExitCode, out string stdOut, out string stdErr); Assert.Equal(exitCode, dotnetTraceExitCode); - Assert.Contains($"Process exited with code '{exitCode}'.", stdOut); } - [Theory] - [InlineData("0 this is a message", new string[] { "\nthis\n", "\nis\n", "\na\n" })] - public void VerifyHideIO(string commandLineArg, string[] stringsInOutput) + [SkippableTheory, MemberData(nameof(Configurations))] + public void VerifyHideIO(TestConfiguration config) { - string exitCodeTraceePath = CommonHelper.GetTraceePathWithArgs(traceeName: "ExitCodeTracee", targetFramework: "net5.0"); - - LaunchDotNetTrace($"collect -o VerifyHideIO.nettrace -- {CommonHelper.HostExe} {exitCodeTraceePath} {commandLineArg}", out int dotnetTraceExitCode, out string stdOut, out string stdErr); + LaunchDotNetTrace(config, "collect -o VerifyHideIO.nettrace", "0 this is a message", out int dotnetTraceExitCode, out string stdOut, out string stdErr); Assert.Equal(0, dotnetTraceExitCode); stdOut = stdOut.Replace("\r", ""); + string[] stringsInOutput = new string[] { "\nthis\n", "\nis\n", "\na\n" }; foreach (string s in stringsInOutput) Assert.DoesNotContain(s, stdOut); } - [Theory] - [InlineData("0 this is a message", new string[] { "\nthis\n", "\nis\n", "\na\n" })] - public void VerifyShowIO(string commandLineArg, string[] stringsInOutput) + [SkippableTheory, MemberData(nameof(Configurations))] + public void VerifyShowIO(TestConfiguration config) { - string exitCodeTraceePath = CommonHelper.GetTraceePathWithArgs(traceeName: "ExitCodeTracee", targetFramework: "net5.0"); - - LaunchDotNetTrace($"collect -o VerifyShowIO.nettrace --show-child-io -- {CommonHelper.HostExe} {exitCodeTraceePath} {commandLineArg}", out int dotnetTraceExitCode, out string stdOut, out string stdErr); + LaunchDotNetTrace(config, "collect -o VerifyShowIO.nettrace --show-child-io", "0 this is a message", out int dotnetTraceExitCode, out string stdOut, out string stdErr); Assert.Equal(0, dotnetTraceExitCode); stdOut = stdOut.Replace("\r", ""); + string[] stringsInOutput = new string[] { "\nthis\n", "\nis\n", "\na\n" }; foreach (string s in stringsInOutput) Assert.Contains(s, stdOut); } diff --git a/src/tests/dotnet-trace/DotnetTrace.UnitTests.csproj b/src/tests/dotnet-trace/DotnetTrace.UnitTests.csproj index 5c99730da2..fb372850fe 100644 --- a/src/tests/dotnet-trace/DotnetTrace.UnitTests.csproj +++ b/src/tests/dotnet-trace/DotnetTrace.UnitTests.csproj @@ -1,13 +1,12 @@ - + - net5.0 + net6.0 - - - + + diff --git a/src/tests/eventpipe/EventPipe.UnitTests.csproj b/src/tests/eventpipe/EventPipe.UnitTests.csproj index f6c26727c4..efa46f1b5c 100644 --- a/src/tests/eventpipe/EventPipe.UnitTests.csproj +++ b/src/tests/eventpipe/EventPipe.UnitTests.csproj @@ -1,7 +1,7 @@ - + - netcoreapp3.1 + $(UnitTestTargetFrameworks) diff --git a/src/tests/eventpipe/GCEvents.cs b/src/tests/eventpipe/GCEvents.cs index ad36377fa2..02f4fd5093 100644 --- a/src/tests/eventpipe/GCEvents.cs +++ b/src/tests/eventpipe/GCEvents.cs @@ -10,6 +10,8 @@ using EventPipe.UnitTests.Common; using Microsoft.Diagnostics.NETCore.Client; using Microsoft.Diagnostics.Tracing; +using System.Reflection; +using System.Runtime.InteropServices; namespace EventPipe.UnitTests.GCEventsValidation { @@ -188,8 +190,16 @@ await RemoteTestExecutorHelper.RunTestCaseAsync(() => Action _eventGeneratingAction = () => { List testList = new List(); - for(int i = 0; i < 100000000; i ++) + for (int i = 0; i < 100_000_000; i ++) { + // This test was failing (no GCFreeSegment callbacks) on x86 until this GC Collects happened. + if (RuntimeInformation.ProcessArchitecture == Architecture.X86) + { + if (i % 1_000_000 == 0) + { + GC.Collect(); + } + } string t = "Test string!"; testList.Add(t); } @@ -216,7 +226,9 @@ await RemoteTestExecutorHelper.RunTestCaseAsync(() => Logger.logger.Log("GCCreateSegmentEvents: " + GCCreateSegmentEvents); Logger.logger.Log("GCFreeSegmentEvents: " + GCFreeSegmentEvents); - bool GCSegmentResult = GCCreateSegmentEvents > 0 && GCFreeSegmentEvents > 0; + + // Disable checking GCFreeSegmentEvents on .NET 7.0 issue: https://github.com/dotnet/diagnostics/issues/3143 + bool GCSegmentResult = GCCreateSegmentEvents > 0 && (GCFreeSegmentEvents > 0 || Environment.Version.Major >= 7); Logger.logger.Log("GCSegmentResult: " + GCSegmentResult); Logger.logger.Log("GCAllocationTickEvents: " + GCAllocationTickEvents); diff --git a/src/tests/eventpipe/LoaderEvents.cs b/src/tests/eventpipe/LoaderEvents.cs index 6f68063aa7..50c21c4ebb 100644 --- a/src/tests/eventpipe/LoaderEvents.cs +++ b/src/tests/eventpipe/LoaderEvents.cs @@ -54,7 +54,7 @@ await RemoteTestExecutorHelper.RunTestCaseAsync(() => GetAssemblyPath(); try { - for(int i=0; i<100; i++) + for (int i = 0; i < 100; i++) { if (i % 10 == 0) Logger.logger.Log($"Load/Unload Assembly {i} times..."); @@ -62,6 +62,7 @@ await RemoteTestExecutorHelper.RunTestCaseAsync(() => assemblyLoad.LoadFromAssemblyPath(assemblyPath+"\\Microsoft.Diagnostics.Runtime.dll"); assemblyLoad.Unload(); } + GC.Collect(); } catch(Exception ex) {