diff --git a/src/Microsoft.TestPlatform.Execution.Shared/Microsoft.TestPlatform.Execution.Shared.projitems b/src/Microsoft.TestPlatform.Execution.Shared/Microsoft.TestPlatform.Execution.Shared.projitems index de0ddc3ab4..2269ef03d4 100644 --- a/src/Microsoft.TestPlatform.Execution.Shared/Microsoft.TestPlatform.Execution.Shared.projitems +++ b/src/Microsoft.TestPlatform.Execution.Shared/Microsoft.TestPlatform.Execution.Shared.projitems @@ -10,6 +10,7 @@ + diff --git a/src/Microsoft.TestPlatform.Execution.Shared/ProcDumpExecutableHelper.cs b/src/Microsoft.TestPlatform.Execution.Shared/ProcDumpExecutableHelper.cs new file mode 100644 index 0000000000..a81ff801c2 --- /dev/null +++ b/src/Microsoft.TestPlatform.Execution.Shared/ProcDumpExecutableHelper.cs @@ -0,0 +1,116 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.IO; + +using Microsoft.VisualStudio.TestPlatform.CoreUtilities; +using Microsoft.VisualStudio.TestPlatform.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions; +using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces; +using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces; + +namespace Microsoft.VisualStudio.TestPlatform.Execution; + +internal class ProcDumpExecutableHelper +{ + private const string ProcdumpUnixProcess = "procdump"; + + private readonly IProcessHelper _processHelper; + private readonly IFileHelper _fileHelper; + private readonly IEnvironment _environment; + private readonly IEnvironmentVariableHelper _environmentVariableHelper; + + public ProcDumpExecutableHelper(IProcessHelper processHelper, IFileHelper fileHelper, IEnvironment environment, IEnvironmentVariableHelper environmentVariableHelper) + { + _processHelper = processHelper; + _fileHelper = fileHelper; + _environment = environment; + _environmentVariableHelper = environmentVariableHelper; + } + + public static string ProcDumpFileName(PlatformArchitecture architecture) => + architecture switch + { + PlatformArchitecture.X86 => "procdump.exe", + PlatformArchitecture.ARM64 => "procdump64a.exe", + _ => "procdump64.exe", + }; + + public bool TryGetProcDumpExecutable(out string path) + { + // Use machine architecture + var targetProcessArchitecture = _environment.Architecture; + return TryGetProcDumpExecutable(targetProcessArchitecture, out path); + } + + public bool TryGetProcDumpExecutable(int processId, out string path) + { + // Launch proc dump according to process architecture + var targetProcessArchitecture = _processHelper.GetProcessArchitecture(processId); + return TryGetProcDumpExecutable(targetProcessArchitecture, out path); + } + + public bool TryGetProcDumpExecutable(PlatformArchitecture architecture, out string path) + { + var procdumpDirectory = _environmentVariableHelper.GetEnvironmentVariable("PROCDUMP_PATH"); + var searchPath = false; + if (procdumpDirectory.IsNullOrWhiteSpace()) + { + EqtTrace.Verbose("ProcDumpExecutableHelper.GetProcDumpExecutable: PROCDUMP_PATH env variable is empty will try to run ProcDump from PATH."); + searchPath = true; + } + else if (!_fileHelper.DirectoryExists(procdumpDirectory)) + { + EqtTrace.Verbose($"ProcDumpExecutableHelper.GetProcDumpExecutable: PROCDUMP_PATH env variable '{procdumpDirectory}' is not a directory, or the directory does not exist. Will try to run ProcDump from PATH."); + searchPath = true; + } + + string filename = _environment.OperatingSystem == PlatformOperatingSystem.Windows + ? ProcDumpFileName(architecture) + : _environment.OperatingSystem is PlatformOperatingSystem.Unix or PlatformOperatingSystem.OSX + ? ProcdumpUnixProcess + : throw new NotSupportedException($"Not supported platform {_environment.OperatingSystem}"); + + if (!searchPath) + { + var candidatePath = Path.Combine(procdumpDirectory!, filename); + if (_fileHelper.Exists(candidatePath)) + { + EqtTrace.Verbose($"ProcDumpExecutableHelper.GetProcDumpExecutable: Path to ProcDump '{candidatePath}' exists, using that."); + path = candidatePath; + return true; + } + + EqtTrace.Verbose($"ProcDumpExecutableHelper.GetProcDumpExecutable: Path '{candidatePath}' does not exist will try to run {filename} from PATH."); + } + + if (TryGetExecutablePath(filename, out var p)) + { + EqtTrace.Verbose($"ProcDumpExecutableHelper.GetProcDumpExecutable: Resolved {filename} to {p} from PATH."); + path = p; + return true; + } + + EqtTrace.Verbose($"ProcDumpExecutableHelper.GetProcDumpExecutable: Could not find {filename} on PATH."); + path = filename; + return false; + } + + private bool TryGetExecutablePath(string executable, out string executablePath) + { + executablePath = string.Empty; + var pathString = _environmentVariableHelper.GetEnvironmentVariable("PATH") ?? string.Empty; + foreach (string path in pathString.Split(Path.PathSeparator)) + { + string exeFullPath = Path.Combine(path.Trim(), executable); + if (_fileHelper.Exists(exeFullPath)) + { + executablePath = exeFullPath; + return true; + } + } + + return false; + } +} diff --git a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/ProcDumpDumper.cs b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/ProcDumpDumper.cs index 0752e9a95a..4436f79ff1 100644 --- a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/ProcDumpDumper.cs +++ b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/ProcDumpDumper.cs @@ -9,6 +9,8 @@ using System.IO; using System.Linq; +using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Helpers; +using Microsoft.VisualStudio.TestPlatform.Execution; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions; using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces; @@ -29,6 +31,7 @@ public class ProcDumpDumper : ICrashDumper, IHangDumper private readonly IProcessHelper _processHelper; private readonly IFileHelper _fileHelper; private readonly IEnvironment _environment; + private readonly IEnvironmentVariableHelper _environmentVariableHelper; private Process? _procDumpProcess; private string? _tempDirectory; private string? _dumpFileName; @@ -36,19 +39,30 @@ public class ProcDumpDumper : ICrashDumper, IHangDumper private string? _outputDirectory; private Process? _process; private string? _outputFilePrefix; + private readonly ProcDumpExecutableHelper _procDumpExecutableHelper; public ProcDumpDumper() - : this(new ProcessHelper(), new FileHelper(), new PlatformEnvironment()) + : this(new ProcessHelper(), new FileHelper(), new PlatformEnvironment(), new EnvironmentVariableHelper()) { } - public ProcDumpDumper(IProcessHelper processHelper, IFileHelper fileHelper, IEnvironment environment) + public ProcDumpDumper(IProcessHelper processHelper, IFileHelper fileHelper, IEnvironment environment) : + this(processHelper, fileHelper, environment, new EnvironmentVariableHelper()) { _processHelper = processHelper; _fileHelper = fileHelper; _environment = environment; } + internal ProcDumpDumper(IProcessHelper processHelper, IFileHelper fileHelper, IEnvironment environment, IEnvironmentVariableHelper environmentVariableHelper) + { + _processHelper = processHelper; + _fileHelper = fileHelper; + _environment = environment; + _environmentVariableHelper = environmentVariableHelper; + _procDumpExecutableHelper = new ProcDumpExecutableHelper(processHelper, fileHelper, environment, environmentVariableHelper); + } + [SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Part of the public API")] protected Action OutputReceivedCallback => (process, data) => // useful for visibility when debugging this tool @@ -86,7 +100,7 @@ public void AttachToTargetProcess(int processId, string outputDirectory, DumpTyp throw new InvalidOperationException("Procdump crash dump file must end with .dmp extension."); } - if (!TryGetProcDumpExecutable(processId, out var procDumpPath)) + if (!_procDumpExecutableHelper.TryGetProcDumpExecutable(processId, out var procDumpPath)) { var procdumpNotFound = string.Format(CultureInfo.CurrentCulture, Resources.Resources.ProcDumpNotFound, procDumpPath); logWarning(procdumpNotFound); @@ -205,7 +219,7 @@ public void Dump(int processId, string outputDirectory, DumpTypeOption dumpType) throw new InvalidOperationException("Procdump crash dump file must end with .dmp extension."); } - if (!TryGetProcDumpExecutable(processId, out var procDumpPath)) + if (!_procDumpExecutableHelper.TryGetProcDumpExecutable(processId, out var procDumpPath)) { var err = $"{procDumpPath} could not be found, please set PROCDUMP_PATH environment variable to a directory that contains {procDumpPath} executable, or make sure that the executable is available on PATH."; ConsoleOutput.Instance.Warning(false, err); @@ -237,90 +251,4 @@ public void Dump(int processId, string outputDirectory, DumpTypeOption dumpType) EqtTrace.Info($"ProcDumpDumper.Dump: ProcDump finished hang dumping process with id '{processId}'."); } - - /// - /// Try get proc dump executable path from env variable or PATH, if it does not success the result is false, and the name of the exe we tried to find. - /// - /// - /// Process Id to determine the bittness - /// - /// - /// Path to procdump or the name of the executable we tried to resolve when we don't find it - /// - /// proc dump executable path - private bool TryGetProcDumpExecutable(int processId, out string path) - { - var procdumpDirectory = Environment.GetEnvironmentVariable("PROCDUMP_PATH"); - var searchPath = false; - if (procdumpDirectory.IsNullOrWhiteSpace()) - { - EqtTrace.Verbose("ProcDumpDumper.GetProcDumpExecutable: PROCDUMP_PATH env variable is empty will try to run ProcDump from PATH."); - searchPath = true; - } - else if (!Directory.Exists(procdumpDirectory)) - { - EqtTrace.Verbose($"ProcDumpDumper.GetProcDumpExecutable: PROCDUMP_PATH env variable '{procdumpDirectory}' is not a directory, or the directory does not exist. Will try to run ProcDump from PATH."); - searchPath = true; - } - - string filename; - if (_environment.OperatingSystem == PlatformOperatingSystem.Windows) - { - // Launch proc dump according to process architecture - var targetProcessArchitecture = _processHelper.GetProcessArchitecture(processId); - filename = targetProcessArchitecture switch - { - PlatformArchitecture.X86 => "procdump.exe", - PlatformArchitecture.ARM64 => "procdump64a.exe", - _ => "procdump64.exe", - }; - } - else - { - filename = _environment.OperatingSystem is PlatformOperatingSystem.Unix or PlatformOperatingSystem.OSX - ? Constants.ProcdumpUnixProcess - : throw new NotSupportedException($"Not supported platform {_environment.OperatingSystem}"); - } - - if (!searchPath) - { - var candidatePath = Path.Combine(procdumpDirectory!, filename); - if (File.Exists(candidatePath)) - { - EqtTrace.Verbose($"ProcDumpDumper.GetProcDumpExecutable: Path to ProcDump '{candidatePath}' exists, using that."); - path = candidatePath; - return true; - } - - EqtTrace.Verbose($"ProcDumpDumper.GetProcDumpExecutable: Path '{candidatePath}' does not exist will try to run {filename} from PATH."); - } - - if (TryGetExecutablePath(filename, out var p)) - { - EqtTrace.Verbose($"ProcDumpDumper.GetProcDumpExecutable: Resolved {filename} to {p} from PATH."); - path = p; - return true; - } - - EqtTrace.Verbose($"ProcDumpDumper.GetProcDumpExecutable: Could not find {filename} on PATH."); - path = filename; - return false; - } - - private bool TryGetExecutablePath(string executable, out string executablePath) - { - executablePath = string.Empty; - var pathString = Environment.GetEnvironmentVariable("PATH") ?? string.Empty; - foreach (string path in pathString.Split(Path.PathSeparator)) - { - string exeFullPath = Path.Combine(path.Trim(), executable); - if (_fileHelper.Exists(exeFullPath)) - { - executablePath = exeFullPath; - return true; - } - } - - return false; - } } diff --git a/src/vstest.console/Processors/AeDebuggerArgumentProcessor.cs b/src/vstest.console/Processors/AeDebuggerArgumentProcessor.cs index c76cd78234..5f4b5ad9a6 100644 --- a/src/vstest.console/Processors/AeDebuggerArgumentProcessor.cs +++ b/src/vstest.console/Processors/AeDebuggerArgumentProcessor.cs @@ -10,6 +10,8 @@ using System.Linq; using Microsoft.VisualStudio.TestPlatform.CommandLine.Processors.Utilities; +using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Helpers; +using Microsoft.VisualStudio.TestPlatform.Execution; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions; using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces; @@ -31,7 +33,7 @@ internal class AeDebuggerArgumentProcessor : IArgumentProcessor public Lazy? Executor { get => _executor ??= new Lazy(() => - new AeDebuggerArgumentExecutor(new PlatformEnvironment(), new FileHelper(), new ProcessHelper(), ConsoleOutput.Instance)); + new AeDebuggerArgumentExecutor(new PlatformEnvironment(), new FileHelper(), new ProcessHelper(), ConsoleOutput.Instance, new EnvironmentVariableHelper())); set => _executor = value; } @@ -67,15 +69,18 @@ internal class AeDebuggerArgumentExecutor : IArgumentExecutor private readonly IFileHelper _fileHelper; private readonly IProcessHelper _processHelper; private readonly IOutput _output; + private readonly IEnvironmentVariableHelper _environmentVariableHelper; private string? _argument; private Dictionary? _collectDumpParameters; - - public AeDebuggerArgumentExecutor(IEnvironment environment, IFileHelper fileHelper, IProcessHelper processHelper, IOutput output) + private readonly ProcDumpExecutableHelper _procDumpExecutableHelper; + public AeDebuggerArgumentExecutor(IEnvironment environment, IFileHelper fileHelper, IProcessHelper processHelper, IOutput output, IEnvironmentVariableHelper environmentVariableHelper) { _environment = environment ?? throw new ArgumentNullException(nameof(environment)); _fileHelper = fileHelper ?? throw new ArgumentNullException(nameof(fileHelper)); _processHelper = processHelper ?? throw new ArgumentNullException(nameof(processHelper)); _output = output ?? throw new ArgumentNullException(nameof(output)); + _environmentVariableHelper = environmentVariableHelper ?? throw new ArgumentNullException(nameof(environmentVariableHelper)); + _procDumpExecutableHelper = new ProcDumpExecutableHelper(processHelper, fileHelper, environment, environmentVariableHelper); } public void Initialize(string? argument) => _argument = argument; @@ -123,21 +128,31 @@ private ArgumentProcessorResult InstallUnistallPostmortemDebugger(bool install) return ArgumentProcessorResult.Fail; } - // Validate ProcDumpToolDirectoryPath - if (!TryGetDirectoryInfo(_collectDumpParameters, - "ProcDumpToolDirectoryPath", - CommandLineResources.ProcDumpToolDirectoryPathArgumenNotFound, - CommandLineResources.InvalidProcDumpToolDirectoryPath, - out DirectoryInfo? procDumpToolDirectoryPath)) + // Look for procdump + string? procDumpPath = null; + if (!TryGetDirectoryInfo(_collectDumpParameters, "ProcDumpToolDirectoryPath", out DirectoryInfo? procDumpToolDirectoryPath) && + !_procDumpExecutableHelper.TryGetProcDumpExecutable(out procDumpPath) + ) { + _output.Error(false, string.Format(CultureInfo.CurrentCulture, CommandLineResources.InvalidProcDumpToolDirectoryPath)); + return ArgumentProcessorResult.Fail; + } + + if (procDumpPath is null && procDumpToolDirectoryPath is not null) + { + procDumpPath = Path.Combine(procDumpToolDirectoryPath.FullName, ProcDumpExecutableHelper.ProcDumpFileName(_environment.Architecture)); + } + + if (procDumpPath is null) + { + _output.Error(false, string.Format(CultureInfo.CurrentCulture, CommandLineResources.ProcDumpFileNameNotFound, procDumpPath)); return ArgumentProcessorResult.Fail; } // Looking for procdump*.exe - FileInfo procDumpFileName = new(Path.Combine(procDumpToolDirectoryPath.FullName, ProcDumpFileName())); - if (!_fileHelper.Exists(procDumpFileName.FullName)) + if (!_fileHelper.Exists(procDumpPath)) { - _output.Error(false, string.Format(CultureInfo.CurrentCulture, CommandLineResources.ProcDumpFileNameNotFound, procDumpFileName.FullName)); + _output.Error(false, string.Format(CultureInfo.CurrentCulture, CommandLineResources.ProcDumpFileNameNotFound, procDumpPath)); return ArgumentProcessorResult.Fail; } @@ -145,7 +160,7 @@ private ArgumentProcessorResult InstallUnistallPostmortemDebugger(bool install) if (install) { // Validate ProcDumpDirectoryPath - if (!TryGetDirectoryInfo(_collectDumpParameters, + if (!TryGetDirectoryInfoAndReportToOutput(_collectDumpParameters, "DumpDirectoryPath", CommandLineResources.ProcDumpDirectoryPathArgumenNotFound, CommandLineResources.InvalidProcDumpDirectoryPath, @@ -157,7 +172,7 @@ private ArgumentProcessorResult InstallUnistallPostmortemDebugger(bool install) procDumpInstallUnistallArgument = dumpDirectoryPath.FullName; } - if (_processHelper.LaunchProcess(procDumpFileName.FullName, install ? "-ma -i" : "-u", procDumpInstallUnistallArgument, null, + if (_processHelper.LaunchProcess(procDumpPath, install ? "-ma -i" : "-u", procDumpInstallUnistallArgument, null, (_, data) => { if (data is not null && !StringUtilities.IsNullOrWhiteSpace(data)) @@ -183,15 +198,7 @@ private ArgumentProcessorResult InstallUnistallPostmortemDebugger(bool install) // We suppose a success if the object returned by the LaunchProcess is not a Process object. return ArgumentProcessorResult.Success; - string ProcDumpFileName() => - _processHelper.GetCurrentProcessArchitecture() switch - { - PlatformArchitecture.X86 => "procdump.exe", - PlatformArchitecture.ARM64 => "procdump64a.exe", - _ => "procdump64.exe", - }; - - bool TryGetDirectoryInfo(Dictionary collectDumpParameters, + bool TryGetDirectoryInfoAndReportToOutput(Dictionary collectDumpParameters, string directoryArgumentName, string invalidArgumentErrorMessage, string invalidDirectoryErrorMessage, @@ -221,6 +228,30 @@ bool TryGetDirectoryInfo(Dictionary collectDumpParameters, return true; } + + bool TryGetDirectoryInfo(Dictionary collectDumpParameters, string directoryArgumentName, [NotNullWhen(true)] out DirectoryInfo? directoryInfo) + { + directoryInfo = null; + + if (!collectDumpParameters.TryGetValue(directoryArgumentName, out string? directoryPath)) + { + return false; + } + + if (directoryPath is null) + { + return false; + } + + directoryInfo = new(directoryPath); + if (!_fileHelper.DirectoryExists(directoryInfo.FullName)) + { + directoryInfo = null; + return false; + } + + return true; + } } } diff --git a/src/vstest.console/Resources/Resources.Designer.cs b/src/vstest.console/Resources/Resources.Designer.cs index 1b5aa9870b..61cecdd3c2 100644 --- a/src/vstest.console/Resources/Resources.Designer.cs +++ b/src/vstest.console/Resources/Resources.Designer.cs @@ -859,7 +859,7 @@ internal static string InvalidProcDumpDirectoryPath { } /// - /// Looks up a localized string similar to The directory specified is not valid: '{0}'. + /// Looks up a localized string similar to The directory specified for the procdump executable is not valid and the tool was not found inside environment variables(PROCDUMP_PATH, PATH). /// internal static string InvalidProcDumpToolDirectoryPath { get { diff --git a/src/vstest.console/Resources/Resources.resx b/src/vstest.console/Resources/Resources.resx index f4638cc23c..bf730bc653 100644 --- a/src/vstest.console/Resources/Resources.resx +++ b/src/vstest.console/Resources/Resources.resx @@ -761,7 +761,7 @@ Postmortem debugger is not supported in the current OS. - The directory specified is not valid: '{0}' + The directory specified for the procdump executable is not valid and the tool was not found inside environment variables (PROCDUMP_PATH, PATH) The directory specified is not valid: '{0}' diff --git a/src/vstest.console/Resources/xlf/Resources.cs.xlf b/src/vstest.console/Resources/xlf/Resources.cs.xlf index 3aee9ba8e5..50df0ff5a3 100644 --- a/src/vstest.console/Resources/xlf/Resources.cs.xlf +++ b/src/vstest.console/Resources/xlf/Resources.cs.xlf @@ -1210,7 +1210,7 @@ - The directory specified is not valid: '{0}' + The directory specified for the procdump executable is not valid and the tool was not found inside environment variables(PROCDUMP_PATH, PATH) The directory specified is not valid: '{0}' diff --git a/src/vstest.console/Resources/xlf/Resources.de.xlf b/src/vstest.console/Resources/xlf/Resources.de.xlf index d749440907..af86ba3247 100644 --- a/src/vstest.console/Resources/xlf/Resources.de.xlf +++ b/src/vstest.console/Resources/xlf/Resources.de.xlf @@ -1210,7 +1210,7 @@ - The directory specified is not valid: '{0}' + The directory specified for the procdump executable is not valid and the tool was not found inside environment variables(PROCDUMP_PATH, PATH) The directory specified is not valid: '{0}' diff --git a/src/vstest.console/Resources/xlf/Resources.es.xlf b/src/vstest.console/Resources/xlf/Resources.es.xlf index 26a64b43ad..3c1bc19b54 100644 --- a/src/vstest.console/Resources/xlf/Resources.es.xlf +++ b/src/vstest.console/Resources/xlf/Resources.es.xlf @@ -1213,7 +1213,7 @@ - The directory specified is not valid: '{0}' + The directory specified for the procdump executable is not valid and the tool was not found inside environment variables(PROCDUMP_PATH, PATH) The directory specified is not valid: '{0}' diff --git a/src/vstest.console/Resources/xlf/Resources.fr.xlf b/src/vstest.console/Resources/xlf/Resources.fr.xlf index 5fabb61fc3..acbb40d86b 100644 --- a/src/vstest.console/Resources/xlf/Resources.fr.xlf +++ b/src/vstest.console/Resources/xlf/Resources.fr.xlf @@ -1210,7 +1210,7 @@ Comportements actuellement pris en charge : - The directory specified is not valid: '{0}' + The directory specified for the procdump executable is not valid and the tool was not found inside environment variables(PROCDUMP_PATH, PATH) The directory specified is not valid: '{0}' diff --git a/src/vstest.console/Resources/xlf/Resources.it.xlf b/src/vstest.console/Resources/xlf/Resources.it.xlf index da3099dbba..cec2b186d6 100644 --- a/src/vstest.console/Resources/xlf/Resources.it.xlf +++ b/src/vstest.console/Resources/xlf/Resources.it.xlf @@ -1210,7 +1210,7 @@ - The directory specified is not valid: '{0}' + The directory specified for the procdump executable is not valid and the tool was not found inside environment variables(PROCDUMP_PATH, PATH) The directory specified is not valid: '{0}' diff --git a/src/vstest.console/Resources/xlf/Resources.ja.xlf b/src/vstest.console/Resources/xlf/Resources.ja.xlf index a2af9460dd..5d4b0a19e5 100644 --- a/src/vstest.console/Resources/xlf/Resources.ja.xlf +++ b/src/vstest.console/Resources/xlf/Resources.ja.xlf @@ -1210,7 +1210,7 @@ - The directory specified is not valid: '{0}' + The directory specified for the procdump executable is not valid and the tool was not found inside environment variables(PROCDUMP_PATH, PATH) The directory specified is not valid: '{0}' diff --git a/src/vstest.console/Resources/xlf/Resources.ko.xlf b/src/vstest.console/Resources/xlf/Resources.ko.xlf index 8765fe950b..151d3c02fc 100644 --- a/src/vstest.console/Resources/xlf/Resources.ko.xlf +++ b/src/vstest.console/Resources/xlf/Resources.ko.xlf @@ -1210,7 +1210,7 @@ - The directory specified is not valid: '{0}' + The directory specified for the procdump executable is not valid and the tool was not found inside environment variables(PROCDUMP_PATH, PATH) The directory specified is not valid: '{0}' diff --git a/src/vstest.console/Resources/xlf/Resources.pl.xlf b/src/vstest.console/Resources/xlf/Resources.pl.xlf index 2bad9edd7c..dd988e71a2 100644 --- a/src/vstest.console/Resources/xlf/Resources.pl.xlf +++ b/src/vstest.console/Resources/xlf/Resources.pl.xlf @@ -1210,7 +1210,7 @@ - The directory specified is not valid: '{0}' + The directory specified for the procdump executable is not valid and the tool was not found inside environment variables(PROCDUMP_PATH, PATH) The directory specified is not valid: '{0}' diff --git a/src/vstest.console/Resources/xlf/Resources.pt-BR.xlf b/src/vstest.console/Resources/xlf/Resources.pt-BR.xlf index 52ed3b9f76..00e0557076 100644 --- a/src/vstest.console/Resources/xlf/Resources.pt-BR.xlf +++ b/src/vstest.console/Resources/xlf/Resources.pt-BR.xlf @@ -1210,7 +1210,7 @@ Altere o prefixo de nível de diagnóstico do agente de console, como mostrado a - The directory specified is not valid: '{0}' + The directory specified for the procdump executable is not valid and the tool was not found inside environment variables(PROCDUMP_PATH, PATH) The directory specified is not valid: '{0}' diff --git a/src/vstest.console/Resources/xlf/Resources.ru.xlf b/src/vstest.console/Resources/xlf/Resources.ru.xlf index f6576ade2a..963f1612ee 100644 --- a/src/vstest.console/Resources/xlf/Resources.ru.xlf +++ b/src/vstest.console/Resources/xlf/Resources.ru.xlf @@ -1210,7 +1210,7 @@ - The directory specified is not valid: '{0}' + The directory specified for the procdump executable is not valid and the tool was not found inside environment variables(PROCDUMP_PATH, PATH) The directory specified is not valid: '{0}' diff --git a/src/vstest.console/Resources/xlf/Resources.tr.xlf b/src/vstest.console/Resources/xlf/Resources.tr.xlf index 781772ec4b..66980721c6 100644 --- a/src/vstest.console/Resources/xlf/Resources.tr.xlf +++ b/src/vstest.console/Resources/xlf/Resources.tr.xlf @@ -1210,7 +1210,7 @@ Günlükler için izleme düzeyini aşağıda gösterildiği gibi değiştirin - The directory specified is not valid: '{0}' + The directory specified for the procdump executable is not valid and the tool was not found inside environment variables(PROCDUMP_PATH, PATH) The directory specified is not valid: '{0}' diff --git a/src/vstest.console/Resources/xlf/Resources.xlf b/src/vstest.console/Resources/xlf/Resources.xlf index e3c822c1b0..d11bcd4780 100644 --- a/src/vstest.console/Resources/xlf/Resources.xlf +++ b/src/vstest.console/Resources/xlf/Resources.xlf @@ -1004,7 +1004,7 @@ Format : TestRunParameters.Parameter(name="<name>", value="<value>") - The directory specified is not valid: '{0}' + The directory specified for the procdump executable is not valid and the tool was not found inside environment variables(PROCDUMP_PATH, PATH) The directory specified is not valid: '{0}' diff --git a/src/vstest.console/Resources/xlf/Resources.zh-Hans.xlf b/src/vstest.console/Resources/xlf/Resources.zh-Hans.xlf index c4c28ba139..2e95f0195f 100644 --- a/src/vstest.console/Resources/xlf/Resources.zh-Hans.xlf +++ b/src/vstest.console/Resources/xlf/Resources.zh-Hans.xlf @@ -1210,7 +1210,7 @@ - The directory specified is not valid: '{0}' + The directory specified for the procdump executable is not valid and the tool was not found inside environment variables(PROCDUMP_PATH, PATH) The directory specified is not valid: '{0}' diff --git a/src/vstest.console/Resources/xlf/Resources.zh-Hant.xlf b/src/vstest.console/Resources/xlf/Resources.zh-Hant.xlf index 851944d827..c8950503c2 100644 --- a/src/vstest.console/Resources/xlf/Resources.zh-Hant.xlf +++ b/src/vstest.console/Resources/xlf/Resources.zh-Hant.xlf @@ -1210,7 +1210,7 @@ - The directory specified is not valid: '{0}' + The directory specified for the procdump executable is not valid and the tool was not found inside environment variables(PROCDUMP_PATH, PATH) The directory specified is not valid: '{0}' diff --git a/test/vstest.console.UnitTests/Processors/AeDebuggerArgumentProcessorTest.cs b/test/vstest.console.UnitTests/Processors/AeDebuggerArgumentProcessorTest.cs index 41daddbd58..8fb031ca0d 100644 --- a/test/vstest.console.UnitTests/Processors/AeDebuggerArgumentProcessorTest.cs +++ b/test/vstest.console.UnitTests/Processors/AeDebuggerArgumentProcessorTest.cs @@ -25,11 +25,12 @@ public class AeDebuggerArgumentProcessorTest private readonly Mock _fileHelper = new(); private readonly Mock _processHelper = new(); private readonly Mock _output = new(); + private readonly Mock _environmentVariableHelper = new(); private readonly AeDebuggerArgumentExecutor _executor; public AeDebuggerArgumentProcessorTest() { - _executor = new AeDebuggerArgumentExecutor(_environment.Object, _fileHelper.Object, _processHelper.Object, _output.Object); + _executor = new AeDebuggerArgumentExecutor(_environment.Object, _fileHelper.Object, _processHelper.Object, _output.Object, _environmentVariableHelper.Object); } [TestMethod] @@ -58,10 +59,11 @@ public void AeDebuggerArgumentProcessorReturnsCorrectTypes() [TestMethod] public void AeDebuggerArgumentExecutor_InvalidCtor() { - Assert.ThrowsException(() => new AeDebuggerArgumentExecutor(_environment.Object, _fileHelper.Object, _processHelper.Object, null!)); - Assert.ThrowsException(() => new AeDebuggerArgumentExecutor(_environment.Object, _fileHelper.Object, null!, _output.Object)); - Assert.ThrowsException(() => new AeDebuggerArgumentExecutor(_environment.Object, null!, _processHelper.Object, _output.Object)); - Assert.ThrowsException(() => new AeDebuggerArgumentExecutor(null!, _fileHelper.Object, _processHelper.Object, _output.Object)); + Assert.ThrowsException(() => new AeDebuggerArgumentExecutor(_environment.Object, _fileHelper.Object, _processHelper.Object, _output.Object, null!)); + Assert.ThrowsException(() => new AeDebuggerArgumentExecutor(_environment.Object, _fileHelper.Object, _processHelper.Object, null!, _environmentVariableHelper.Object)); + Assert.ThrowsException(() => new AeDebuggerArgumentExecutor(_environment.Object, _fileHelper.Object, null!, _output.Object, _environmentVariableHelper.Object)); + Assert.ThrowsException(() => new AeDebuggerArgumentExecutor(_environment.Object, null!, _processHelper.Object, _output.Object, _environmentVariableHelper.Object)); + Assert.ThrowsException(() => new AeDebuggerArgumentExecutor(null!, _fileHelper.Object, _processHelper.Object, _output.Object, _environmentVariableHelper.Object)); } [TestMethod] @@ -100,11 +102,25 @@ public void AeDebuggerArgumentExecutor_WrongDirectoryPaths(string command, strin _fileHelper.Setup(x => x.DirectoryExists(It.IsAny())) .Returns((string path) => directoryPath is null || !directoryPath.EndsWith(path)); _fileHelper.Setup(x => x.Exists(It.IsAny())) - .Returns((string path) => path.EndsWith("procdump.exe")); + .Returns((string path) => path.EndsWith("procdump.exe") && path != "procdump.exe"); _executor.Initialize(string.Format(CultureInfo.InvariantCulture, command, directoryPath)); Assert.AreEqual(ArgumentProcessorResult.Fail, _executor.Execute()); } + [TestMethod] + [DataRow("Install;DumpDirectoryPath=c:\\DumpDirectoryPath", "PROCDUMP_PATH", "c:\\procDump")] + [DataRow("Install;DumpDirectoryPath=c:\\DumpDirectoryPath", "PATH", "c:\\procDump;")] + + public void AeDebuggerArgumentExecutor_ShouldUseEnvironmentVariables(string command, string environmentVariablesKey, string environmentVariableValue) + { + _environmentVariableHelper.Setup(x => x.GetEnvironmentVariable(environmentVariablesKey)).Returns(environmentVariableValue); + _fileHelper.Setup(x => x.DirectoryExists("c:\\procDump")).Returns(true); + _fileHelper.Setup(x => x.DirectoryExists("c:\\DumpDirectoryPath")).Returns(true); + _fileHelper.Setup(x => x.Exists(It.IsAny())).Returns((string fileName) => fileName == "c:\\procDump\\procdump.exe"); + _executor.Initialize(command); + Assert.AreEqual(ArgumentProcessorResult.Success, _executor.Execute()); + } + [TestMethod] [DataRow("Install;ProcDumpToolDirectoryPath=c:\\ProcDumpToolDirectoryPath;DumpDirectoryPath=c:\\DumpDirectoryPath", true)] [DataRow("Uninstall;ProcDumpToolDirectoryPath=c:\\ProcDumpToolDirectoryPath;DumpDirectoryPath=c:\\DumpDirectoryPath", false)]