Thanks to visit codestin.com
Credit goes to github.com

Skip to content

If tests are taking too long, create a memory dump and abort #1052

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

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
114 changes: 113 additions & 1 deletion src/embed_tests/GlobalTestsSetup.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,40 @@
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;

using Microsoft.Win32.SafeHandles;
using NUnit.Framework;
using Python.Runtime;

namespace Python.EmbeddingTest
{

// As the SetUpFixture, the OneTimeTearDown of this class is executed after
// all tests have run.
[SetUpFixture]
public class GlobalTestsSetup
{
[OneTimeSetUp]
public void GlobalSetup()
{
if (!Debugger.IsAttached)
{
new Thread(() =>
{
Thread.Sleep(TimeSpan.FromSeconds(30));
UploadDump();
Console.Error.WriteLine("Test has been running for too long. Created memory dump");
Environment.Exit(1);
})
{
IsBackground = true,
}.Start();
}
}

[OneTimeTearDown]
public void FinalCleanup()
{
Expand All @@ -17,5 +43,91 @@ public void FinalCleanup()
PythonEngine.Shutdown();
}
}

static void UploadDump()
{
var self = Process.GetCurrentProcess();

const string dumpPath = "memory.dmp";

// ensure DbgHelp is loaded
MiniDumpWriteDump(IntPtr.Zero, 0, IntPtr.Zero,
MiniDumpType.WithFullMemory | MiniDumpType.IgnoreInaccessibleMemory,
IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);

using (var fileHandle = CreateFile(dumpPath, FileAccess.Write, FileShare.Write,
securityAttrs: IntPtr.Zero, dwCreationDisposition: FileMode.Create, dwFlagsAndAttributes: 0,
hTemplateFile: IntPtr.Zero))
{
if (fileHandle.IsInvalid)
throw new Win32Exception();

if (!MiniDumpWriteDump(self.Handle, self.Id, fileHandle.DangerousGetHandle(), MiniDumpType.Normal,
causeException: IntPtr.Zero, userStream: IntPtr.Zero, callback: IntPtr.Zero))
throw new Win32Exception();
}

const string archivePath = "memory.zip";
string filesToPack = '"' + dumpPath + '"';
filesToPack += ' ' + GetFilesToPackFor(Assembly.GetExecutingAssembly());
filesToPack += ' ' + GetFilesToPackFor(typeof(PyObject).Assembly);

Process.Start("7z", $"a {archivePath} {filesToPack}").WaitForExit();
Process.Start("appveyor", arguments: $"PushArtifact -Path \"{archivePath}\"").WaitForExit();
}

static string GetFilesToPackFor(Assembly assembly)
{
string result = '"' + assembly.Location + '"';
string pdb = Path.ChangeExtension(assembly.Location, ".pdb");
if (File.Exists(pdb))
{
result += $" \"{pdb}\"";
}
return result;
}

[DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
private static extern SafeFileHandle CreateFile(
string lpFileName,
FileAccess dwDesiredAccess,
FileShare dwShareMode,
IntPtr securityAttrs,
FileMode dwCreationDisposition,
int dwFlagsAndAttributes,
IntPtr hTemplateFile);
[DllImport("DbgHelp", SetLastError = true)]
static extern bool MiniDumpWriteDump(IntPtr hProcess,
int processID, IntPtr hFile, MiniDumpType dumpType,
IntPtr causeException, IntPtr userStream, IntPtr callback);

[Flags]
enum MiniDumpType
{
Normal = 0x00000000,
WithDataSegments = 0x00000001,
WithFullMemory = 0x00000002,
WithHandleData = 0x00000004,
FilterMemory = 0x00000008,
ScanMemory = 0x00000010,
WithUnloadedModules = 0x00000020,
WithIndirectlyReferencedMemory = 0x00000040,
FilterModulePaths = 0x00000080,
WithProcessThreadData = 0x00000100,
WithPrivateReadWriteMemory = 0x00000200,
WithoutOptionalData = 0x00000400,
WithFullMemoryInfo = 0x00000800,
WithThreadInfo = 0x00001000,
WithCodeSegments = 0x00002000,
WithoutAuxiliaryState = 0x00004000,
WithFullAuxiliaryState = 0x00008000,
WithPrivateWriteCopyMemory = 0x00010000,
IgnoreInaccessibleMemory = 0x00020000,
WithTokenInformation = 0x00040000,
WithModuleHeaders = 0x00080000,
FilterTriage = 0x00100000,
WithAvxXStateContext = 0x00200000,
ValidTypeFlags = 0x003fffff,
}
}
}
2 changes: 1 addition & 1 deletion src/embed_tests/TestDomainReload.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ static void RunAssemblyAndUnload(Assembly assembly, string assemblyName)
{
Console.WriteLine($"[Program.Main] The Proxy object is valid ({theProxy}). Unexpected domain unload behavior");
}
catch (Exception)
catch (AppDomainUnloadedException)
{
Console.WriteLine("[Program.Main] The Proxy object is not valid anymore, domain unload complete.");
}
Expand Down