diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/SocketCommunicationManager.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/SocketCommunicationManager.cs
index 093a19b7d2..bc9a5b0208 100644
--- a/src/Microsoft.TestPlatform.CommunicationUtilities/SocketCommunicationManager.cs
+++ b/src/Microsoft.TestPlatform.CommunicationUtilities/SocketCommunicationManager.cs
@@ -70,6 +70,11 @@ public class SocketCommunicationManager : ICommunicationManager
///
private object sendSyncObject = new object();
+ ///
+ /// Sync object for receiving messages
+ ///
+ private object receiveSyncObject = new object();
+
private Socket socket;
///
@@ -311,7 +316,11 @@ public async Task ReceiveMessageAsync(CancellationToken cancellationTok
/// Raw message string
public string ReceiveRawMessage()
{
- return this.binaryReader.ReadString();
+ lock (this.receiveSyncObject)
+ {
+ // Reading message on binaryreader is not thread-safe
+ return this.binaryReader.ReadString();
+ }
}
///
diff --git a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/BlameCollector.cs b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/BlameCollector.cs
index 9ac6ea5605..316d07317d 100644
--- a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/BlameCollector.cs
+++ b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/BlameCollector.cs
@@ -30,6 +30,8 @@ public class BlameCollector : DataCollector, ITestExecutionEnvironmentSpecifier
private int testStartCount;
private int testEndCount;
private bool processDumpEnabled;
+ private bool collectDumpAlways;
+ private bool processFullDumpEnabled;
private string attachmentGuid;
///
@@ -97,12 +99,50 @@ public override void Initialize(
if (this.configurationElement != null)
{
- this.processDumpEnabled = this.configurationElement[Constants.DumpModeKey] != null;
+ var collectDumpNode = this.configurationElement[Constants.DumpModeKey];
+ this.processDumpEnabled = collectDumpNode != null;
+ if (this.processDumpEnabled)
+ {
+ this.ValidateAndAddProcessDumpParameters(collectDumpNode);
+ }
}
this.attachmentGuid = Guid.NewGuid().ToString().Replace("-", string.Empty);
}
+ private void ValidateAndAddProcessDumpParameters(XmlElement collectDumpNode)
+ {
+ foreach (XmlAttribute attribute in collectDumpNode.Attributes)
+ {
+ if (string.Equals(attribute.Name, Constants.CollectDumpAlwaysKey, StringComparison.OrdinalIgnoreCase))
+ {
+ if (string.Equals(attribute.Value, Constants.TrueConfigurationValue, StringComparison.OrdinalIgnoreCase) || string.Equals(attribute.Value, Constants.FalseConfigurationValue, StringComparison.OrdinalIgnoreCase))
+ {
+ bool.TryParse(attribute.Value, out this.collectDumpAlways);
+ }
+ else
+ {
+ this.logger.LogWarning(this.context.SessionDataCollectionContext, string.Format(CultureInfo.CurrentUICulture, Resources.Resources.BlameParameterValueIncorrect, attribute.Name, Constants.TrueConfigurationValue, Constants.FalseConfigurationValue));
+ }
+ }
+ else if (string.Equals(attribute.Name, Constants.DumpTypeKey, StringComparison.OrdinalIgnoreCase))
+ {
+ if (string.Equals(attribute.Value, Constants.FullConfigurationValue, StringComparison.OrdinalIgnoreCase) || string.Equals(attribute.Value, Constants.MiniConfigurationValue, StringComparison.OrdinalIgnoreCase))
+ {
+ this.processFullDumpEnabled = string.Equals(attribute.Value, Constants.FullConfigurationValue, StringComparison.OrdinalIgnoreCase);
+ }
+ else
+ {
+ this.logger.LogWarning(this.context.SessionDataCollectionContext, string.Format(CultureInfo.CurrentUICulture, Resources.Resources.BlameParameterValueIncorrect, attribute.Name, Constants.FullConfigurationValue, Constants.MiniConfigurationValue));
+ }
+ }
+ else
+ {
+ this.logger.LogWarning(this.context.SessionDataCollectionContext, string.Format(CultureInfo.CurrentUICulture, Resources.Resources.BlameParameterKeyIncorrect, attribute.Name));
+ }
+ }
+ }
+
///
/// Called when Test Case Start event is invoked
///
@@ -159,23 +199,29 @@ private void SessionEnded_Handler(object sender, SessionEndEventArgs args)
if (this.processDumpEnabled)
{
- try
+ // If there was a test case crash or if we need to collect dump on process exit.
+ if (this.testStartCount > this.testEndCount || this.collectDumpAlways)
{
- var dumpFile = this.processDumpUtility.GetDumpFile();
- if (!string.IsNullOrEmpty(dumpFile))
+ try
{
- var fileTranferInformation = new FileTransferInformation(this.context.SessionDataCollectionContext, dumpFile, true);
- this.dataCollectionSink.SendFileAsync(fileTranferInformation);
+ var dumpFile = this.processDumpUtility.GetDumpFile();
+ if (!string.IsNullOrEmpty(dumpFile))
+ {
+ var fileTranferInformation = new FileTransferInformation(this.context.SessionDataCollectionContext, dumpFile, true);
+ this.dataCollectionSink.SendFileAsync(fileTranferInformation);
+ }
+ else
+ {
+ EqtTrace.Warning("BlameCollector.SessionEnded_Handler: blame:CollectDump was enabled but dump file was not generated.");
+ this.logger.LogWarning(args.Context, Resources.Resources.ProcDumpNotGenerated);
+ }
}
- else
+ catch (FileNotFoundException ex)
{
- EqtTrace.Warning("BlameCollector.SessionEnded_Handler: blame:CollectDump was enabled but dump file was not generated.");
+ EqtTrace.Warning(ex.Message);
+ this.logger.LogWarning(args.Context, ex.Message);
}
}
- catch (FileNotFoundException ex)
- {
- this.logger.LogWarning(args.Context, ex.Message);
- }
}
this.DeregisterEvents();
@@ -195,7 +241,7 @@ private void TestHostLaunched_Handler(object sender, TestHostLaunchedEventArgs a
try
{
- this.processDumpUtility.StartProcessDump(args.TestHostProcessId, this.attachmentGuid, this.GetResultsDirectory());
+ this.processDumpUtility.StartProcessDump(args.TestHostProcessId, this.attachmentGuid, this.GetResultsDirectory(), this.processFullDumpEnabled);
}
catch (TestPlatformException e)
{
@@ -204,7 +250,7 @@ private void TestHostLaunched_Handler(object sender, TestHostLaunchedEventArgs a
EqtTrace.Warning("BlameCollector.TestHostLaunched_Handler: Could not start process dump. {0}", e);
}
- this.logger.LogWarning(args.Context, e.Message);
+ this.logger.LogWarning(args.Context, string.Format(CultureInfo.CurrentUICulture, Resources.Resources.ProcDumpCouldNotStart, e.Message));
}
catch (Exception e)
{
@@ -213,7 +259,7 @@ private void TestHostLaunched_Handler(object sender, TestHostLaunchedEventArgs a
EqtTrace.Warning("BlameCollector.TestHostLaunched_Handler: Could not start process dump. {0}", e);
}
- this.logger.LogWarning(args.Context, e.ToString());
+ this.logger.LogWarning(args.Context, string.Format(CultureInfo.CurrentUICulture, Resources.Resources.ProcDumpCouldNotStart, e.ToString()));
}
}
diff --git a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Constants.cs b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Constants.cs
index f060ab8a0a..a69e025599 100644
--- a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Constants.cs
+++ b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Constants.cs
@@ -42,5 +42,35 @@ internal static class Constants
/// Configuration key name for dump mode
///
public const string DumpModeKey = "CollectDump";
+
+ ///
+ /// Configuration key name for collect dump always
+ ///
+ public const string CollectDumpAlwaysKey = "CollectAlways";
+
+ ///
+ /// Configuration key name for dump type
+ ///
+ public const string DumpTypeKey = "DumpType";
+
+ ///
+ /// Configuration value for true
+ ///
+ public const string TrueConfigurationValue = "True";
+
+ ///
+ /// Configuration value for false
+ ///
+ public const string FalseConfigurationValue = "False";
+
+ ///
+ /// Configuration value for full
+ ///
+ public const string FullConfigurationValue = "Full";
+
+ ///
+ /// Configuration value for mini
+ ///
+ public const string MiniConfigurationValue = "Mini";
}
}
diff --git a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Interfaces/IProcessDumpUtility.cs b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Interfaces/IProcessDumpUtility.cs
index 7240edd688..5aff12e962 100644
--- a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Interfaces/IProcessDumpUtility.cs
+++ b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Interfaces/IProcessDumpUtility.cs
@@ -27,6 +27,9 @@ public interface IProcessDumpUtility
///
/// Path to TestResults directory
///
- void StartProcessDump(int processId, string dumpFileGuid, string testResultsDirectory);
+ ///
+ /// Is full dump enabled
+ ///
+ void StartProcessDump(int processId, string dumpFileGuid, string testResultsDirectory, bool isFullDump = false);
}
}
diff --git a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/ProcessDumpUtility.cs b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/ProcessDumpUtility.cs
index 34388a84b1..56ef19d6d4 100644
--- a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/ProcessDumpUtility.cs
+++ b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/ProcessDumpUtility.cs
@@ -71,14 +71,14 @@ public string GetDumpFile()
}
///
- public void StartProcessDump(int processId, string dumpFileGuid, string testResultsDirectory)
+ public void StartProcessDump(int processId, string dumpFileGuid, string testResultsDirectory, bool isFullDump = false)
{
this.dumpFileName = $"{this.processHelper.GetProcessName(processId)}_{processId}_{dumpFileGuid}";
this.testResultsDirectory = testResultsDirectory;
this.procDumpProcess = this.processHelper.LaunchProcess(
this.GetProcDumpExecutable(),
- ProcessDumpUtility.BuildProcDumpArgs(processId, this.dumpFileName),
+ ProcessDumpUtility.BuildProcDumpArgs(processId, this.dumpFileName, isFullDump),
testResultsDirectory,
null,
null,
@@ -94,13 +94,24 @@ public void StartProcessDump(int processId, string dumpFileGuid, string testResu
///
/// Filename for dump file
///
+ ///
+ /// Is full dump enabled
+ ///
/// Arguments
- private static string BuildProcDumpArgs(int processId, string filename)
+ private static string BuildProcDumpArgs(int processId, string filename, bool isFullDump = false)
{
// -accepteula: Auto accept end-user license agreement
// -t: Write a dump when the process terminates.
- // This will create a minidump of the process with specified filename
- return "-accepteula -t " + processId + " " + filename + ".dmp";
+ if (isFullDump)
+ {
+ // This will create a fulldump of the process with specified filename
+ return "-accepteula -t -ma " + processId + " " + filename + ".dmp";
+ }
+ else
+ {
+ // This will create a minidump of the process with specified filename
+ return "-accepteula -t " + processId + " " + filename + ".dmp";
+ }
}
///
diff --git a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Resources/Resources.Designer.cs b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Resources/Resources.Designer.cs
index d62173d17d..959f718ca8 100644
--- a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Resources/Resources.Designer.cs
+++ b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Resources/Resources.Designer.cs
@@ -69,6 +69,39 @@ internal static string AbortedTestRun {
}
}
+ ///
+ /// The blame parameter key specified {0} is not valid. Ignoring this key..
+ ///
+ internal static string BlameParameterKeyIncorrect
+ {
+ get
+ {
+ return ResourceManager.GetString("BlameParameterKeyIncorrect", resourceCulture);
+ }
+ }
+
+ ///
+ /// The blame parameter key {0} can only support values {1}/{2}. Ignoring this key..
+ ///
+ internal static string BlameParameterValueIncorrect
+ {
+ get
+ {
+ return ResourceManager.GetString("BlameParameterValueIncorrect", resourceCulture);
+ }
+ }
+
+ ///
+ /// Could not start process dump: {0}.
+ ///
+ internal static string ProcDumpCouldNotStart
+ {
+ get
+ {
+ return ResourceManager.GetString("ProcDumpCouldNotStart", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Required environment variable PROCDUMP_PATH was null or empty. Set PROCDUMP_PATH to path of folder containing appropriate procdump executable.
///
@@ -80,6 +113,17 @@ internal static string ProcDumpEnvVarEmpty
}
}
+ ///
+ /// CollectDump was enabled but dump file was not generated..
+ ///
+ internal static string ProcDumpNotGenerated
+ {
+ get
+ {
+ return ResourceManager.GetString("ProcDumpNotGenerated", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Collect dump was enabled but no dump file was generated.
///
diff --git a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Resources/Resources.resx b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Resources/Resources.resx
index 8264dc43a3..1106193219 100644
--- a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Resources/Resources.resx
+++ b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Resources/Resources.resx
@@ -120,10 +120,22 @@
The active Test Run was aborted because the host process exited unexpectedly while executing following test(s):
+
+ The blame parameter key specified {0} is not valid. Ignoring this key.
+
+
+ The blame parameter key {0} can only support values {1}/{2}. Ignoring this key.
+
Collect dump was enabled but no dump file was generated.
+
+ Could not start process dump: {0}
+
Required environment variable PROCDUMP_PATH was null or empty. Set PROCDUMP_PATH to path of folder containing appropriate procdump executable.
+
+ CollectDump was enabled but dump file was not generated.
+
\ No newline at end of file
diff --git a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Resources/xlf/Resources.cs.xlf b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Resources/xlf/Resources.cs.xlf
index 3d9d7d20e5..940447921f 100644
--- a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Resources/xlf/Resources.cs.xlf
+++ b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Resources/xlf/Resources.cs.xlf
@@ -35,6 +35,26 @@
Bylo povoleno shromáždění výpisu, ale nebyl vygenerován žádný soubor výpisu.
+
+
+ The blame parameter key {0} is not valid. Ignoring this parameter.
+
+
+
+
+ The blame parameter key {0} can only support values {1}/{2}. Ignoring this parameter.
+
+
+
+
+ Could not start process dump: {0}
+
+
+
+
+ CollectDump was enabled but dump file was not generated.
+
+