From c00aedfec91990bf1ebb3aaa5ca4b29f4522964f Mon Sep 17 00:00:00 2001 From: nohwnd Date: Mon, 17 Aug 2020 14:35:05 +0200 Subject: [PATCH 1/4] Add env vars --- .../BlameCollector.cs | 10 +++++++++- ...t.TestPlatform.Extensions.BlameDataCollector.csproj | 3 +-- src/testhost.x86/testhost.x86.csproj | 2 +- src/testhost/testhost.csproj | 2 +- ...form.Extensions.BlameDataCollector.UnitTests.csproj | 2 +- ...soft.TestPlatform.TestHostProvider.UnitTests.csproj | 2 +- 6 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/BlameCollector.cs b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/BlameCollector.cs index 49db170b95..d04d98c9e8 100644 --- a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/BlameCollector.cs +++ b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/BlameCollector.cs @@ -139,11 +139,19 @@ public override void Initialize( this.environmentVariables.Add(new KeyValuePair("COMPlus_DbgEnableElfDumpOnMacOS", "1")); this.environmentVariables.Add(new KeyValuePair("COMPlus_DbgEnableMiniDump", "1")); + if (!this.processFullDumpEnabled) + { + // https://github.com/dotnet/coreclr/blob/master/Documentation/botr/xplat-minidump-generation.md + // MiniDumpWithPrivateReadWriteMemory = 2 + // MiniDumpNormal = 1 + this.environmentVariables.Add(new KeyValuePair("COMPlus_DbgMiniDumpType", this.processFullDumpEnabled ? "2" : "1")); + } + var guid = Guid.NewGuid().ToString(); var dumpDirectory = Path.Combine(Path.GetTempPath(), guid); Directory.CreateDirectory(dumpDirectory); - var dumpPath = Path.Combine(dumpDirectory, $"dotnet_%d_crashdump.dmp"); + var dumpPath = Path.Combine(dumpDirectory, $"%e_%p_%t_crashdump.dmp"); this.environmentVariables.Add(new KeyValuePair("COMPlus_DbgMiniDumpName", dumpPath)); } diff --git a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Microsoft.TestPlatform.Extensions.BlameDataCollector.csproj b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Microsoft.TestPlatform.Extensions.BlameDataCollector.csproj index a29f60e15c..c44d1babca 100644 --- a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Microsoft.TestPlatform.Extensions.BlameDataCollector.csproj +++ b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Microsoft.TestPlatform.Extensions.BlameDataCollector.csproj @@ -23,7 +23,7 @@ - + @@ -34,7 +34,6 @@ 0.2.0-preview.20378.10 - diff --git a/src/testhost.x86/testhost.x86.csproj b/src/testhost.x86/testhost.x86.csproj index 67a3bf57a8..535a6e6afb 100644 --- a/src/testhost.x86/testhost.x86.csproj +++ b/src/testhost.x86/testhost.x86.csproj @@ -30,7 +30,7 @@ true - + diff --git a/src/testhost/testhost.csproj b/src/testhost/testhost.csproj index 8b57e6b9f1..c239485d24 100644 --- a/src/testhost/testhost.csproj +++ b/src/testhost/testhost.csproj @@ -32,7 +32,7 @@ true - + diff --git a/test/Microsoft.TestPlatform.Extensions.BlameDataCollector.UnitTests/Microsoft.TestPlatform.Extensions.BlameDataCollector.UnitTests.csproj b/test/Microsoft.TestPlatform.Extensions.BlameDataCollector.UnitTests/Microsoft.TestPlatform.Extensions.BlameDataCollector.UnitTests.csproj index 84c0db3ec3..b472cd5412 100644 --- a/test/Microsoft.TestPlatform.Extensions.BlameDataCollector.UnitTests/Microsoft.TestPlatform.Extensions.BlameDataCollector.UnitTests.csproj +++ b/test/Microsoft.TestPlatform.Extensions.BlameDataCollector.UnitTests/Microsoft.TestPlatform.Extensions.BlameDataCollector.UnitTests.csproj @@ -19,7 +19,7 @@ - + diff --git a/test/Microsoft.TestPlatform.TestHostProvider.UnitTests/Microsoft.TestPlatform.TestHostProvider.UnitTests.csproj b/test/Microsoft.TestPlatform.TestHostProvider.UnitTests/Microsoft.TestPlatform.TestHostProvider.UnitTests.csproj index ac42301ead..bd0cbba8ac 100644 --- a/test/Microsoft.TestPlatform.TestHostProvider.UnitTests/Microsoft.TestPlatform.TestHostProvider.UnitTests.csproj +++ b/test/Microsoft.TestPlatform.TestHostProvider.UnitTests/Microsoft.TestPlatform.TestHostProvider.UnitTests.csproj @@ -14,7 +14,7 @@ - + From 34abdb507de72f235dd2eac6c081c9cf6e84a30f Mon Sep 17 00:00:00 2001 From: nohwnd Date: Mon, 17 Aug 2020 15:55:07 +0200 Subject: [PATCH 2/4] Create sequence file even if not crashed --- .../BlameCollector.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/BlameCollector.cs b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/BlameCollector.cs index d04d98c9e8..807951336a 100644 --- a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/BlameCollector.cs +++ b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/BlameCollector.cs @@ -419,14 +419,11 @@ private void SessionEndedHandler(object sender, SessionEndEventArgs args) // If the last test crashes, it will not invoke a test case end and therefore // In case of crash testStartCount will be greater than testEndCount and we need to write the sequence // And send the attachment - if (this.testStartCount > this.testEndCount) - { - var filepath = Path.Combine(this.GetTempDirectory(), Constants.AttachmentFileName + "_" + this.attachmentGuid); + var filepath = Path.Combine(this.GetTempDirectory(), Constants.AttachmentFileName + "_" + this.attachmentGuid); - filepath = this.blameReaderWriter.WriteTestSequence(this.testSequence, this.testObjectDictionary, filepath); - var fileTranferInformation = new FileTransferInformation(this.context.SessionDataCollectionContext, filepath, true); - this.dataCollectionSink.SendFileAsync(fileTranferInformation); - } + filepath = this.blameReaderWriter.WriteTestSequence(this.testSequence, this.testObjectDictionary, filepath); + var fti = new FileTransferInformation(this.context.SessionDataCollectionContext, filepath, true); + this.dataCollectionSink.SendFileAsync(fti); if (this.collectProcessDumpOnTrigger) { From 2a7c18a9d7daa58e70cedf5459f68375ae338a30 Mon Sep 17 00:00:00 2001 From: nohwnd Date: Mon, 17 Aug 2020 17:13:18 +0200 Subject: [PATCH 3/4] Fix net5.0 version comparisons --- .../CrashDumperFactory.cs | 19 ++++++++++++++++- .../HangDumperFactory.cs | 21 +++++++++++++++++-- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/CrashDumperFactory.cs b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/CrashDumperFactory.cs index 44ea5dc379..867e9acb4f 100644 --- a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/CrashDumperFactory.cs +++ b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/CrashDumperFactory.cs @@ -6,12 +6,29 @@ namespace Microsoft.TestPlatform.Extensions.BlameDataCollector using System; using System.Runtime.InteropServices; using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using NuGet.Frameworks; internal class CrashDumperFactory : ICrashDumperFactory { public ICrashDumper Create(string targetFramework) { + if (targetFramework is null) + { + throw new ArgumentNullException(nameof(targetFramework)); + } + EqtTrace.Info($"CrashDumperFactory: Creating dumper for {RuntimeInformation.OSDescription} with target framework {targetFramework}."); + + var tfm = NuGetFramework.Parse(targetFramework); + + if (tfm == null || tfm.IsUnsupported) + { + EqtTrace.Error($"CrashDumperFactory: Could not parse target framework {targetFramework}, to a supported framework version."); + throw new NotSupportedException($"Could not parse target framework {targetFramework}, to a supported framework version."); + } + + var isNet50OrNewer = tfm.Framework == ".NETCoreApp" && tfm.Version >= Version.Parse("5.0.0.0"); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { EqtTrace.Info($"CrashDumperFactory: This is Windows, returning ProcDumpCrashDumper that uses ProcDump utility."); @@ -28,7 +45,7 @@ public ICrashDumper Create(string targetFramework) // return new NetClientCrashDumper(); } - if (!string.IsNullOrWhiteSpace(targetFramework) && targetFramework.Contains("v5.0")) + if (isNet50OrNewer) { EqtTrace.Info($"CrashDumperFactory: This is {RuntimeInformation.OSDescription} on {targetFramework} .NETClient dumper which uses env variables to collect crashdumps of testhost and any child process."); return new NetClientCrashDumper(); diff --git a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/HangDumperFactory.cs b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/HangDumperFactory.cs index cde59dc0bc..6f9b8d0dad 100644 --- a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/HangDumperFactory.cs +++ b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/HangDumperFactory.cs @@ -6,12 +6,27 @@ namespace Microsoft.TestPlatform.Extensions.BlameDataCollector using System; using System.Runtime.InteropServices; using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using NuGet.Frameworks; internal class HangDumperFactory : IHangDumperFactory { public IHangDumper Create(string targetFramework) { + if (targetFramework is null) + { + throw new ArgumentNullException(nameof(targetFramework)); + } + EqtTrace.Info($"HangDumperFactory: Creating dumper for {RuntimeInformation.OSDescription} with target framework {targetFramework}."); + + var tfm = NuGetFramework.Parse(targetFramework); + + if (tfm == null || tfm.IsUnsupported) + { + EqtTrace.Error($"HangDumperFactory: Could not parse target framework {targetFramework}, to a supported framework version."); + throw new NotSupportedException($"Could not parse target framework {targetFramework}, to a supported framework version."); + } + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { EqtTrace.Info($"HangDumperFactory: This is Windows, returning the default WindowsHangDumper that P/Invokes MiniDumpWriteDump."); @@ -20,7 +35,8 @@ public IHangDumper Create(string targetFramework) if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { - if (!string.IsNullOrWhiteSpace(targetFramework) && targetFramework.Contains("v2.1")) + var isLessThan31 = tfm.Framework == ".NETCoreApp" && tfm.Version < Version.Parse("3.1.0.0"); + if (isLessThan31) { EqtTrace.Info($"HangDumperFactory: This is Linux on netcoreapp2.1, returning SigtrapDumper."); @@ -33,7 +49,8 @@ public IHangDumper Create(string targetFramework) if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { - if (!string.IsNullOrWhiteSpace(targetFramework) && !targetFramework.Contains("v5.0")) + var isLessThan50 = tfm.Framework == ".NETCoreApp" && tfm.Version < Version.Parse("5.0.0.0"); + if (isLessThan50) { EqtTrace.Info($"HangDumperFactory: This is OSX on {targetFramework}, This combination of OS and framework is not supported."); From 21310f42d49fe1650b7fbca21042cbecad3a2665 Mon Sep 17 00:00:00 2001 From: nohwnd Date: Tue, 18 Aug 2020 10:21:05 +0200 Subject: [PATCH 4/4] Print message when sequence is not generated --- .../BlameCollector.cs | 15 +++++++++++---- .../Resources/Resources.Designer.cs | 9 +++++++++ .../Resources/Resources.resx | 4 ++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/BlameCollector.cs b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/BlameCollector.cs index 807951336a..ea0f92321c 100644 --- a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/BlameCollector.cs +++ b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/BlameCollector.cs @@ -419,11 +419,18 @@ private void SessionEndedHandler(object sender, SessionEndEventArgs args) // If the last test crashes, it will not invoke a test case end and therefore // In case of crash testStartCount will be greater than testEndCount and we need to write the sequence // And send the attachment - var filepath = Path.Combine(this.GetTempDirectory(), Constants.AttachmentFileName + "_" + this.attachmentGuid); + if (this.testStartCount > this.testEndCount) + { + var filepath = Path.Combine(this.GetTempDirectory(), Constants.AttachmentFileName + "_" + this.attachmentGuid); - filepath = this.blameReaderWriter.WriteTestSequence(this.testSequence, this.testObjectDictionary, filepath); - var fti = new FileTransferInformation(this.context.SessionDataCollectionContext, filepath, true); - this.dataCollectionSink.SendFileAsync(fti); + filepath = this.blameReaderWriter.WriteTestSequence(this.testSequence, this.testObjectDictionary, filepath); + var fti = new FileTransferInformation(this.context.SessionDataCollectionContext, filepath, true); + this.dataCollectionSink.SendFileAsync(fti); + } + else + { + this.logger.LogWarning(this.context.SessionDataCollectionContext, Resources.Resources.NotGeneratingSequenceFile); + } if (this.collectProcessDumpOnTrigger) { diff --git a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Resources/Resources.Designer.cs b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Resources/Resources.Designer.cs index 96a3ee8a04..5918a0cae6 100644 --- a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Resources/Resources.Designer.cs +++ b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Resources/Resources.Designer.cs @@ -105,6 +105,15 @@ internal static string InactivityTimeout { } } + /// + /// Looks up a localized string similar to All tests finished running, Sequence file will not be generated.. + /// + internal static string NotGeneratingSequenceFile { + get { + return ResourceManager.GetString("NotGeneratingSequenceFile", resourceCulture); + } + } + /// /// Looks up a localized string similar to Could not start process dump: {0}. /// diff --git a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Resources/Resources.resx b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Resources/Resources.resx index 6631dcada8..7918d18973 100644 --- a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Resources/Resources.resx +++ b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Resources/Resources.resx @@ -132,6 +132,10 @@ The specified inactivity time of {0} minute/s has elapsed. Collecting a dump and killing the test host process. + + All tests finished running, Sequence file will not be generated. + "Sequence" is the name of the file. + Could not start process dump: {0}