Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[master] Fix collect dump always #2645

Merged
35 commits merged into from
Nov 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
47fee27
Hide -release in console
nohwnd Jun 5, 2020
9ed42e4
Add param block
nohwnd Jun 8, 2020
6de7aca
Match on whole branch name
nohwnd Jun 8, 2020
b60cf6f
Set var
nohwnd Jun 8, 2020
1fbf4a3
Change assertion
nohwnd Jun 8, 2020
501939e
Trim version
nohwnd Jun 8, 2020
fceebbc
Update dependencies from https://github.com/dotnet/arcade build 20200…
dotnet-maestro[bot] Jun 9, 2020
c449a1e
Update feeds
nohwnd Jun 9, 2020
f777f36
Merge master
nohwnd Jun 9, 2020
2474ad2
Revert to previous dotnet version
nohwnd Jun 9, 2020
df62aca
Added new exception handling (#2461)
Sanan07 Jun 12, 2020
c1b6b2c
Adding test run attachments processing (#2463)
jakubch1 Jul 2, 2020
4ec9fb2
Add environment variables to enable MacOS dump
nohwnd Aug 11, 2020
1d30394
Fixed code coverage compatibility issue (#2527)
cvpoienaru Aug 19, 2020
fd2748b
Forward merge master
nohwnd Aug 21, 2020
f5e870b
Print only whole version on release branch.
nohwnd Aug 21, 2020
c1a6782
Print version of the product in log (#2535)
nohwnd Aug 25, 2020
3454261
Trigger dumps asynchronously (#2533)
nohwnd Aug 26, 2020
088da43
Revert "Trigger dumps asynchronously (#2533)" (#2541)
nohwnd Aug 26, 2020
42b3463
Remove env variables
nohwnd Aug 28, 2020
4fcacb2
Merge branch 'rel/16.8' of https://github.com/microsoft/vstest into r…
nohwnd Aug 28, 2020
b9cd8eb
Remove sleeps and extra process dumps from blame
nohwnd Sep 1, 2020
0c0fafa
Merge branch 'master' of https://github.com/microsoft/vstest into rel…
nohwnd Sep 2, 2020
70a599d
Fix blame parameter, warning, and add all testhosts to be ngend (#2579)
nohwnd Sep 18, 2020
2418d9e
Forward merge fixes from master to rc2 (#2581)
nohwnd Sep 24, 2020
2e615ad
Generate release notes in pipeline
nohwnd Sep 25, 2020
0b1e2e5
Fix the initial assets location of VSTest assets (#2589)
mmitche Oct 9, 2020
b195e25
Signing instructions for Newtonsoft.Json.dll added (#2601) (#2603)
Haplois Oct 22, 2020
d6875ce
Cherry-picked signing fixes from `master` (#2619)
Haplois Nov 5, 2020
d37b3e5
Fix collect dump always
nohwnd Nov 18, 2020
53b5ab6
Fix acceptance tests
nohwnd Nov 19, 2020
3bd148c
Merge branch 'fix-blame-collect-always' into fix-blame-in-16.9
nohwnd Nov 19, 2020
192c8dc
botched merge
nohwnd Nov 19, 2020
ad86eb2
Add regular expressions dependency
nohwnd Nov 19, 2020
e92c9a1
Remove regex
nohwnd Nov 19, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions scripts/build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -818,7 +818,7 @@ function Create-NugetPackages

# Verifies that expected number of files gets shipped in nuget packages.
# Few nuspec uses wildcard characters.
Verify-Nuget-Packages $packageOutputDir
Verify-Nuget-Packages $packageOutputDir $TPB_Version

Write-Log "Create-NugetPackages: Complete. {$(Get-ElapsedTime($timer))}"
}
Expand Down Expand Up @@ -1026,7 +1026,7 @@ function Generate-Manifest
Write-Log "Generate-Manifest: Started."

$sdkTaskPath = Join-Path $env:TP_ROOT_DIR "eng\common\sdk-task.ps1"
& $sdkTaskPath -restore -task GenerateBuildManifest /p:PackagesToPublishPattern=$TPB_PackageOutDir\*.nupkg /p:AssetManifestFilePath=$TPB_PackageOutDir\manifest\manifest.xml /p:ManifestBuildData="Location=https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json" /p:BUILD_BUILDNUMBER=$BuildNumber
& $sdkTaskPath -restore -task GenerateBuildManifest /p:PackagesToPublishPattern=$TPB_PackageOutDir\*.nupkg /p:AssetManifestFilePath=$TPB_PackageOutDir\manifest\manifest.xml /p:ManifestBuildData="Location=https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json" /p:BUILD_BUILDNUMBER=$BuildNumber

Write-Log "Generate-Manifest: Completed."
}
Expand Down
5 changes: 3 additions & 2 deletions scripts/verify-nupkgs.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ function Unzip
[System.IO.Compression.ZipFile]::ExtractToDirectory($zipfile, $outpath)
}

function Verify-Nuget-Packages($packageDirectory)

function Verify-Nuget-Packages($packageDirectory, $version)
{
Write-Log "Starting Verify-Nuget-Packages."
$expectedNumOfFiles = @{
Expand All @@ -23,7 +24,7 @@ function Verify-Nuget-Packages($packageDirectory)
"Microsoft.TestPlatform.TestHost" = 212;
"Microsoft.TestPlatform.TranslationLayer" = 121}

$nugetPackages = Get-ChildItem -Filter "*.nupkg" $packageDirectory | % { $_.FullName}
$nugetPackages = Get-ChildItem -Filter "*$version*.nupkg" $packageDirectory | % { $_.FullName }

Write-VerboseLog "Unzip NuGet packages."
$unzipNugetPackageDirs = New-Object System.Collections.Generic.List[System.Object]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,10 @@ private void SessionEndedHandler(object sender, SessionEndEventArgs args)
}
else
{
this.logger.LogWarning(this.context.SessionDataCollectionContext, Resources.Resources.NotGeneratingSequenceFile);
if (this.collectProcessDumpOnTestHostHang)
{
this.logger.LogWarning(this.context.SessionDataCollectionContext, Resources.Resources.NotGeneratingSequenceFile);
}
}

if (this.uploadDumpFiles)
Expand Down Expand Up @@ -528,7 +531,7 @@ private void TestHostLaunchedHandler(object sender, TestHostLaunchedEventArgs ar
try
{
var dumpDirectory = this.GetDumpDirectory();
this.processDumpUtility.StartTriggerBasedProcessDump(args.TestHostProcessId, dumpDirectory, this.processFullDumpEnabled, this.targetFramework);
this.processDumpUtility.StartTriggerBasedProcessDump(args.TestHostProcessId, dumpDirectory, this.processFullDumpEnabled, this.targetFramework, this.collectDumpAlways);
}
catch (TestPlatformException e)
{
Expand Down Expand Up @@ -585,7 +588,15 @@ private string GetTempDirectory()
{
if (string.IsNullOrWhiteSpace(this.tempDirectory))
{
this.tempDirectory = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
// DUMP_TEMP_PATH will be used as temporary storage location
// for the dumps, this won't affect the dump uploads. Just the place where
// we store them before moving them to the final folder.

// AGENT_TEMPDIRECTORY is AzureDevops variable, which is set to path
// that is cleaned up after every job. This is preferable to use over
// just the normal temp.
var temp = Environment.GetEnvironmentVariable("VSTEST_DUMP_TEMP_PATH") ?? Environment.GetEnvironmentVariable("AGENT_TEMPDIRECTORY") ?? Path.GetTempPath();
this.tempDirectory = Path.Combine(temp, Guid.NewGuid().ToString());
Directory.CreateDirectory(this.tempDirectory);
return this.tempDirectory;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Microsoft.TestPlatform.Extensions.BlameDataCollector
{
public interface ICrashDumper
{
void AttachToTargetProcess(int processId, string outputDirectory, DumpTypeOption dumpType);
void AttachToTargetProcess(int processId, string outputDirectory, DumpTypeOption dumpType, bool collectAlways);

void WaitForDumpToFinish();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ public interface IProcDumpArgsBuilder
/// <param name="isFullDump">
/// Is full dump enabled
/// </param>
/// <param name="collectAlways">
/// Collects the dump on process exit even when there is no exception
/// </param>
/// <returns>Arguments</returns>
string BuildTriggerBasedProcDumpArgs(int processId, string filename, IEnumerable<string> procDumpExceptionsList, bool isFullDump);
string BuildTriggerBasedProcDumpArgs(int processId, string filename, IEnumerable<string> procDumpExceptionsList, bool isFullDump, bool collectAlways);

/// <summary>
/// Arguments for procdump.exe for getting a dump in case of a testhost hang
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ public interface IProcessDumpUtility
/// <param name="targetFramework">
/// The target framework of the process
/// </param>
void StartTriggerBasedProcessDump(int processId, string testResultsDirectory, bool isFullDump, string targetFramework);
/// <param name="collectAlways">
/// Collect the dump on process exit even if there is no exception
/// </param>
void StartTriggerBasedProcessDump(int processId, string testResultsDirectory, bool isFullDump, string targetFramework, bool collectAlways);

/// <summary>
/// Launch proc dump process to capture dump in case of a testhost hang and wait for it to exit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Microsoft.TestPlatform.Extensions.BlameDataCollector
{
internal class NetClientCrashDumper : ICrashDumper
{
public void AttachToTargetProcess(int processId, string outputDirectory, DumpTypeOption dumpType)
public void AttachToTargetProcess(int processId, string outputDirectory, DumpTypeOption dumpType, bool collectAlways)
{
// we don't need to do anything directly here, we setup the env variables
// in the dumper configuration, including the path
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ namespace Microsoft.TestPlatform.Extensions.BlameDataCollector
public class ProcDumpArgsBuilder : IProcDumpArgsBuilder
{
/// <inheritdoc />
public string BuildTriggerBasedProcDumpArgs(int processId, string filename, IEnumerable<string> procDumpExceptionsList, bool isFullDump)
public string BuildTriggerBasedProcDumpArgs(int processId, string filename, IEnumerable<string> procDumpExceptionsList, bool isFullDump, bool collectAlways)
{
// -accepteula: Auto accept end-user license agreement
// -e: Write a dump when the process encounters an unhandled exception. Include the 1 to create dump on first chance exceptions.
// -g: Run as a native debugger in a managed process (no interop).
// -t: Write a dump when the process terminates.
// -ma: Full dump argument.
// -f: Filter the exceptions.
StringBuilder procDumpArgument = new StringBuilder("-accepteula -e 1 -g -t ");
StringBuilder procDumpArgument = new StringBuilder($"-accepteula -e 1 -g {(collectAlways ? "-t " : string.Empty)}");
if (isFullDump)
{
procDumpArgument.Append("-ma ");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public void WaitForDumpToFinish()
}

/// <inheritdoc/>
public void AttachToTargetProcess(int processId, string outputDirectory, DumpTypeOption dumpType)
public void AttachToTargetProcess(int processId, string outputDirectory, DumpTypeOption dumpType, bool collectAlways)
{
var process = Process.GetProcessById(processId);
var outputFile = Path.Combine(outputDirectory, $"{process.ProcessName}_{process.Id}_{DateTime.Now:yyyyMMddTHHmmss}_crashdump.dmp");
Expand All @@ -96,7 +96,8 @@ public void AttachToTargetProcess(int processId, string outputDirectory, DumpTyp
processId,
this.dumpFileName,
ProcDumpExceptionsList,
isFullDump: dumpType == DumpTypeOption.Full);
isFullDump: dumpType == DumpTypeOption.Full,
collectAlways: collectAlways);

EqtTrace.Info($"ProcDumpCrashDumper.AttachToTargetProcess: Running ProcDump with arguments: '{procDumpArgs}'.");
this.procDumpProcess = this.processHelper.LaunchProcess(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,9 @@ public void StartHangBasedProcessDump(int processId, string tempDirectory, bool
}

/// <inheritdoc/>
public void StartTriggerBasedProcessDump(int processId, string testResultsDirectory, bool isFullDump, string targetFramework)
public void StartTriggerBasedProcessDump(int processId, string testResultsDirectory, bool isFullDump, string targetFramework, bool collectAlways)
{
this.CrashDump(processId, testResultsDirectory, isFullDump ? DumpTypeOption.Full : DumpTypeOption.Mini, targetFramework);
this.CrashDump(processId, testResultsDirectory, isFullDump ? DumpTypeOption.Full : DumpTypeOption.Mini, targetFramework, collectAlways);
}

/// <inheritdoc/>
Expand All @@ -109,15 +109,15 @@ public void DetachFromTargetProcess(int targetProcessId)
this.crashDumper?.DetachFromTargetProcess(targetProcessId);
}

private void CrashDump(int processId, string tempDirectory, DumpTypeOption dumpType, string targetFramework)
private void CrashDump(int processId, string tempDirectory, DumpTypeOption dumpType, string targetFramework, bool collectAlways)
{
var processName = this.processHelper.GetProcessName(processId);
EqtTrace.Info($"ProcessDumpUtility.CrashDump: Creating {dumpType.ToString().ToLowerInvariant()} dump of process {processName} ({processId}) into temporary path '{tempDirectory}'.");
this.crashDumpDirectory = tempDirectory;

this.crashDumper = this.crashDumperFactory.Create(targetFramework);
ConsoleOutput.Instance.Information(false, $"Blame: Attaching crash dump utility to process {processName} ({processId}).");
this.crashDumper.AttachToTargetProcess(processId, tempDirectory, dumpType);
this.crashDumper.AttachToTargetProcess(processId, tempDirectory, dumpType, collectAlways);
}

private void HangDump(int processId, string tempDirectory, DumpTypeOption dumpType, string targetFramework, Action<string> logWarning = null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public void BlameDataCollectorShouldGiveCorrectTestCaseName(RunnerInfo runnerInf
arguments = string.Concat(arguments, $" /ResultsDirectory:{resultsDir}");
this.InvokeVsTest(arguments);

this.VaildateOutput();
this.VaildateOutput("BlameUnitTestProject.UnitTest1.TestMethod2");
}

[TestMethod]
Expand All @@ -57,14 +57,51 @@ public void BlameDataCollectorShouldOutputDumpFile(RunnerInfo runnerInfo)
{
Environment.SetEnvironmentVariable("PROCDUMP_PATH", Path.Combine(this.testEnvironment.PackageDirectory, @"procdump\0.0.1\bin"));

AcceptanceTestBase.SetTestEnvironment(this.testEnvironment, runnerInfo);
var assemblyPaths = this.BuildMultipleAssemblyPath("SimpleTestProject3.dll").Trim('\"');
var arguments = PrepareArguments(assemblyPaths, this.GetTestAdapterPath(), string.Empty, string.Empty, runnerInfo.InIsolationValue);
arguments = string.Concat(arguments, $" /Blame:CollectDump");
arguments = string.Concat(arguments, $" /ResultsDirectory:{resultsDir}");
arguments = string.Concat(arguments, " /testcasefilter:ExitWithStackoverFlow");
this.InvokeVsTest(arguments);

this.VaildateOutput("SampleUnitTestProject3.UnitTest1.ExitWithStackoverFlow", validateDumpFile: true);
}

[TestMethod]
[NetFullTargetFrameworkDataSource]
[NetCoreTargetFrameworkDataSource]
public void BlameDataCollectorShouldNotOutputDumpFileWhenNoCrashOccurs(RunnerInfo runnerInfo)
{
Environment.SetEnvironmentVariable("PROCDUMP_PATH", Path.Combine(this.testEnvironment.PackageDirectory, @"procdump\0.0.1\bin"));

AcceptanceTestBase.SetTestEnvironment(this.testEnvironment, runnerInfo);
var assemblyPaths = this.GetAssetFullPath("BlameUnitTestProject.dll");
var assemblyPaths = this.BuildMultipleAssemblyPath("SimpleTestProject.dll").Trim('\"');
var arguments = PrepareArguments(assemblyPaths, this.GetTestAdapterPath(), string.Empty, string.Empty, runnerInfo.InIsolationValue);
arguments = string.Concat(arguments, $" /Blame:CollectDump");
arguments = string.Concat(arguments, $" /ResultsDirectory:{resultsDir}");
arguments = string.Concat(arguments, " /testcasefilter:PassingTest");
this.InvokeVsTest(arguments);

Assert.IsFalse(this.StdOut.Contains(".dmp"), "it should not collect a dump, because nothing crashed");
}

[TestMethod]
[NetFullTargetFrameworkDataSource]
[NetCoreTargetFrameworkDataSource]
public void BlameDataCollectorShouldOutputDumpFileWhenNoCrashOccursButCollectAlwaysIsEnabled(RunnerInfo runnerInfo)
{
Environment.SetEnvironmentVariable("PROCDUMP_PATH", Path.Combine(this.testEnvironment.PackageDirectory, @"procdump\0.0.1\bin"));

AcceptanceTestBase.SetTestEnvironment(this.testEnvironment, runnerInfo);
var assemblyPaths = this.BuildMultipleAssemblyPath("SimpleTestProject.dll").Trim('\"');
var arguments = PrepareArguments(assemblyPaths, this.GetTestAdapterPath(), string.Empty, string.Empty, runnerInfo.InIsolationValue);
arguments = string.Concat(arguments, $" /Blame:CollectDump;CollectAlways=True");
arguments = string.Concat(arguments, $" /ResultsDirectory:{resultsDir}");
arguments = string.Concat(arguments, " /testcasefilter:PassingTest");
this.InvokeVsTest(arguments);

this.VaildateOutput(true);
Assert.IsTrue(this.StdOut.Contains(".dmp"), "it should collect dump, even if nothing crashed");
}

[TestMethod]
Expand Down Expand Up @@ -243,12 +280,12 @@ private void ValidateDump(int expectedDumpCount = 1)
}
}

private void VaildateOutput(bool validateDumpFile = false)
private void VaildateOutput(string testName, bool validateDumpFile = false)
{
bool isSequenceAttachmentReceived = false;
bool isDumpAttachmentReceived = false;
bool isValid = false;
this.StdErrorContains("BlameUnitTestProject.UnitTest1.TestMethod2");
this.StdErrorContains(testName);
this.StdOutputContains("Sequence_");
var resultFiles = Directory.GetFiles(this.resultsDir, "*", SearchOption.AllDirectories);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ public void TriggerTestHostLaunchedHandlerShouldStartProcDumpUtilityIfProcDumpEn
this.mockDataColectionEvents.Raise(x => x.TestHostLaunched += null, new TestHostLaunchedEventArgs(this.dataCollectionContext, 1234));

// Verify StartProcessDumpCall
this.mockProcessDumpUtility.Verify(x => x.StartTriggerBasedProcessDump(1234, It.IsAny<string>(), false, It.IsAny<string>()));
this.mockProcessDumpUtility.Verify(x => x.StartTriggerBasedProcessDump(1234, It.IsAny<string>(), false, It.IsAny<string>(), false));
}

/// <summary>
Expand All @@ -498,7 +498,7 @@ public void TriggerTestHostLaunchedHandlerShouldStartProcDumpUtilityForFullDumpI
this.mockDataColectionEvents.Raise(x => x.TestHostLaunched += null, new TestHostLaunchedEventArgs(this.dataCollectionContext, 1234));

// Verify StartProcessDumpCall
this.mockProcessDumpUtility.Verify(x => x.StartTriggerBasedProcessDump(1234, It.IsAny<string>(), true, It.IsAny<string>()));
this.mockProcessDumpUtility.Verify(x => x.StartTriggerBasedProcessDump(1234, It.IsAny<string>(), true, It.IsAny<string>(), false));
}

/// <summary>
Expand Down Expand Up @@ -527,7 +527,7 @@ public void TriggerTestHostLaunchedHandlerShouldStartProcDumpUtilityForFullDumpI
this.mockDataColectionEvents.Raise(x => x.TestHostLaunched += null, new TestHostLaunchedEventArgs(this.dataCollectionContext, 1234));

// Verify StartProcessDumpCall
this.mockProcessDumpUtility.Verify(x => x.StartTriggerBasedProcessDump(1234, It.IsAny<string>(), true, It.IsAny<string>()));
this.mockProcessDumpUtility.Verify(x => x.StartTriggerBasedProcessDump(1234, It.IsAny<string>(), true, It.IsAny<string>(), false));
}

/// <summary>
Expand Down Expand Up @@ -647,7 +647,7 @@ public void TriggerTestHostLaunchedHandlerShouldCatchTestPlatFormExceptionsAndRe

// Make StartProcessDump throw exception
var tpex = new TestPlatformException("env var exception");
this.mockProcessDumpUtility.Setup(x => x.StartTriggerBasedProcessDump(1234, It.IsAny<string>(), false, It.IsAny<string>()))
this.mockProcessDumpUtility.Setup(x => x.StartTriggerBasedProcessDump(1234, It.IsAny<string>(), false, It.IsAny<string>(), false))
.Throws(tpex);

// Raise TestHostLaunched
Expand All @@ -673,7 +673,7 @@ public void TriggerTestHostLaunchedHandlerShouldCatchAllUnexpectedExceptionsAndR

// Make StartProcessDump throw exception
var ex = new Exception("start process failed");
this.mockProcessDumpUtility.Setup(x => x.StartTriggerBasedProcessDump(1234, It.IsAny<string>(), false, It.IsAny<string>()))
this.mockProcessDumpUtility.Setup(x => x.StartTriggerBasedProcessDump(1234, It.IsAny<string>(), false, It.IsAny<string>(), false))
.Throws(ex);

// Raise TestHostLaunched
Expand Down Expand Up @@ -710,9 +710,9 @@ private XmlElement GetDumpConfigurationElement(

if (collectDumpOnExit)
{
var fulldumpAttribute = xmldoc.CreateAttribute(BlameDataCollector.Constants.CollectDumpAlwaysKey);
fulldumpAttribute.Value = "true";
node.Attributes.Append(fulldumpAttribute);
var collectDumpOnExitAttribute = xmldoc.CreateAttribute(BlameDataCollector.Constants.CollectDumpAlwaysKey);
collectDumpOnExitAttribute.Value = "true";
node.Attributes.Append(collectDumpOnExitAttribute);
}

if (colectDumpOnHang)
Expand Down
Loading