Skip to content

Commit

Permalink
[master] Fix collect dump always (#2645)
Browse files Browse the repository at this point in the history
* Hide -release in console

* Add param block

* Match on whole branch name

* Set var

* Change assertion

* Trim version

* Update dependencies from https://github.com/dotnet/arcade build 20200602.3 (#2456)

Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.SignTool , Microsoft.DotNet.SwaggerGenerator.MSBuild
 From Version 5.0.0-beta.20052.1 -> To Version 1.0.0-beta.20302.3

Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>

* Update feeds

* Revert to previous dotnet version

* Added new exception handling (#2461)

* Test space added

* Exception handler was added to catch AccessDeniedException while trying to create TestResults folder

* Remove unnecessary space

* Deleted unnecessary test. Changed console message and corrected folder path in that message

* Remove unnecessary dot

* Removed unnecessary lines and usings and coreccted exception message

* Removed unnecessary line

* Updating resource files

* New exception handling was added

* Formatted exception message

* Adding test run attachments processing (#2463)

* v1

* Merging v1

* Rename to MultiTestRunsFinalization

* New version

* More changes

* More changes

* Next changes

* Fix

* test

* More changes

* Dmc chagnes

* next

* small changes

* compiled

* More changes

* acceptance tests green

* Review comments #1

* Resolving more comments

* Tests for design mode client

* Tests for events handler

* revert not related changes

* More changes

* Compiling OK, tests OK

* Unit tests for manager

* More changes

* More tests

* tests for reqeust sender

* more tests

* Tests for cancelling

* Acceptance tests done

* Remove not used stuff

* Fix comments

* Fix race condition in test

* Fix another race condition

* Fix converting to xml

* fix next test

* fix test

* Next changes

* Review changes #1

* Fixing multi test finalization manager tests

* Fixes

* Fix last unit test

* Fix acceptance tests

* Progress feature, compiling + unit tests

* acceptance tests changes

* More changes

* Fixing resources accesability

* Fix test

* Fix race conditions in acceptance tests

* RFC changes merged

* Log warning in case of unexpected message id

* Fix spelling

* Additional comment

* Restore some stuff in interfaces

* Big renaming

* Added processingSettings

* Fix naming

* Move explanation to <remarks>

* Add environment variables to enable MacOS dump

* Fixed code coverage compatibility issue (#2527)

Fixed code coverage compatibility issue

* Print version of the product in log (#2535)

* Trigger dumps asynchronously (#2533)

* Run each dump in a task in netclient dumper

* More reasonable timeout

* Revert "Trigger dumps asynchronously (#2533)" (#2541)

This reverts commit 3454261.

* Remove env variables

* Remove sleeps and extra process dumps from blame

* Fix blame parameter, warning, and add all testhosts to be ngend (#2579)

* Forward merge fixes from master to rc2 (#2581)

* Avoid logging >Task returned false but did not log an error.< (#2557)

* Avoid logging >Task returned false but did not log an error.< on test failure

* Add VSTEST_BUILD_DEBUG env var

* Using namespaces

* Invert the switch because it will be still backwards in the final release

* Use bitness from process or OS (#2571)

* Do not force .NET4.5 in case legacy test settings are provided (#2545)

* Do not force .NET4.5 in case legacy test settings are provided

* Net core app

* Fix runconfig

* Default platform

* Generate release notes in pipeline

* Fix the initial assets location of VSTest assets (#2589)

They are being manually pushed to the dotnet-tools feed, not dotnet-core.

* Signing instructions for Newtonsoft.Json.dll added (#2601) (#2603)

* Signing instructions for Newtonsoft.Json.dll added
* Added 3rdParty signature thumbprint to the accept list.

* Cherry-picked signing fixes from `master` (#2619)

* Fix collect dump always

* Fix acceptance tests

* botched merge

* Add regular expressions dependency

* Remove regex

Co-authored-by: dotnet-maestro[bot] <42748379+dotnet-maestro[bot]@users.noreply.github.com>
Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>
Co-authored-by: Sanan Yuzbashiyev <Sanan07@users.noreply.github.com>
Co-authored-by: Jakub Chocholowicz <59966772+jakubch1@users.noreply.github.com>
Co-authored-by: Codrin-Victor Poienaru <cvpoienaru@gmail.com>
Co-authored-by: Matt Mitchell <mmitche@microsoft.com>
Co-authored-by: Medeni Baykal <433724+Haplois@users.noreply.github.com>
  • Loading branch information
8 people committed Nov 20, 2020
1 parent 67689ab commit f2256b8
Show file tree
Hide file tree
Showing 14 changed files with 102 additions and 36 deletions.
4 changes: 2 additions & 2 deletions scripts/build.ps1
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
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
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
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
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
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
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
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
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
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
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
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 @@ public void CleanUp()

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

0 comments on commit f2256b8

Please sign in to comment.