From d58101f10029ff137b1d0dd1dd90f89deb900607 Mon Sep 17 00:00:00 2001 From: Medeni Baykal <433724+Haplois@users.noreply.github.com> Date: Tue, 15 Feb 2022 12:17:23 +0100 Subject: [PATCH 1/2] Added playground project. --- TestPlatform.sln | 35 +++++ playground/MSTest1/MSTest1.csproj | 30 ++++ playground/MSTest1/UnitTest1.cs | 16 +++ playground/README.md | 17 +++ playground/TestPlatform.Playground/Program.cs | 131 ++++++++++++++++++ .../Properties/launchSettings.json | 14 ++ .../TestPlatform.Playground.csproj | 45 ++++++ 7 files changed, 288 insertions(+) create mode 100644 playground/MSTest1/MSTest1.csproj create mode 100644 playground/MSTest1/UnitTest1.cs create mode 100644 playground/README.md create mode 100644 playground/TestPlatform.Playground/Program.cs create mode 100644 playground/TestPlatform.Playground/Properties/launchSettings.json create mode 100644 playground/TestPlatform.Playground/TestPlatform.Playground.csproj diff --git a/TestPlatform.sln b/TestPlatform.sln index fde613978a..0871578e83 100644 --- a/TestPlatform.sln +++ b/TestPlatform.sln @@ -170,6 +170,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DumpMinitool.x86", "src\Dat EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AttachVS", "src\AttachVS\AttachVS.csproj", "{8238A052-D626-49EB-A011-51DC6D0DBA30}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "playground", "playground", "{6CE2F530-582B-4695-A209-41065E103426}" + ProjectSection(SolutionItems) = preProject + playground\README.md = playground\README.md + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestPlatform.Playground", "playground\TestPlatform.Playground\TestPlatform.Playground.csproj", "{545A88D3-1AE2-4D39-9B7C-C691768AD17F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSTest1", "playground\MSTest1\MSTest1.csproj", "{57A61A09-10AD-44BE-8DF4-A6FD108F7DF7}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution src\Microsoft.TestPlatform.Execution.Shared\Microsoft.TestPlatform.Execution.Shared.projitems*{10b6ade1-f808-4612-801d-4452f5b52242}*SharedItemsImports = 5 @@ -835,6 +844,30 @@ Global {8238A052-D626-49EB-A011-51DC6D0DBA30}.Release|x64.Build.0 = Release|Any CPU {8238A052-D626-49EB-A011-51DC6D0DBA30}.Release|x86.ActiveCfg = Release|Any CPU {8238A052-D626-49EB-A011-51DC6D0DBA30}.Release|x86.Build.0 = Release|Any CPU + {545A88D3-1AE2-4D39-9B7C-C691768AD17F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {545A88D3-1AE2-4D39-9B7C-C691768AD17F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {545A88D3-1AE2-4D39-9B7C-C691768AD17F}.Debug|x64.ActiveCfg = Debug|Any CPU + {545A88D3-1AE2-4D39-9B7C-C691768AD17F}.Debug|x64.Build.0 = Debug|Any CPU + {545A88D3-1AE2-4D39-9B7C-C691768AD17F}.Debug|x86.ActiveCfg = Debug|Any CPU + {545A88D3-1AE2-4D39-9B7C-C691768AD17F}.Debug|x86.Build.0 = Debug|Any CPU + {545A88D3-1AE2-4D39-9B7C-C691768AD17F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {545A88D3-1AE2-4D39-9B7C-C691768AD17F}.Release|Any CPU.Build.0 = Release|Any CPU + {545A88D3-1AE2-4D39-9B7C-C691768AD17F}.Release|x64.ActiveCfg = Release|Any CPU + {545A88D3-1AE2-4D39-9B7C-C691768AD17F}.Release|x64.Build.0 = Release|Any CPU + {545A88D3-1AE2-4D39-9B7C-C691768AD17F}.Release|x86.ActiveCfg = Release|Any CPU + {545A88D3-1AE2-4D39-9B7C-C691768AD17F}.Release|x86.Build.0 = Release|Any CPU + {57A61A09-10AD-44BE-8DF4-A6FD108F7DF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {57A61A09-10AD-44BE-8DF4-A6FD108F7DF7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {57A61A09-10AD-44BE-8DF4-A6FD108F7DF7}.Debug|x64.ActiveCfg = Debug|Any CPU + {57A61A09-10AD-44BE-8DF4-A6FD108F7DF7}.Debug|x64.Build.0 = Debug|Any CPU + {57A61A09-10AD-44BE-8DF4-A6FD108F7DF7}.Debug|x86.ActiveCfg = Debug|Any CPU + {57A61A09-10AD-44BE-8DF4-A6FD108F7DF7}.Debug|x86.Build.0 = Debug|Any CPU + {57A61A09-10AD-44BE-8DF4-A6FD108F7DF7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {57A61A09-10AD-44BE-8DF4-A6FD108F7DF7}.Release|Any CPU.Build.0 = Release|Any CPU + {57A61A09-10AD-44BE-8DF4-A6FD108F7DF7}.Release|x64.ActiveCfg = Release|Any CPU + {57A61A09-10AD-44BE-8DF4-A6FD108F7DF7}.Release|x64.Build.0 = Release|Any CPU + {57A61A09-10AD-44BE-8DF4-A6FD108F7DF7}.Release|x86.ActiveCfg = Release|Any CPU + {57A61A09-10AD-44BE-8DF4-A6FD108F7DF7}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -907,6 +940,8 @@ Global {33A20B85-7024-4112-B1E7-00CD0E4A9F96} = {B705537C-B82C-4A30-AFA5-6244D9A7DAEB} {2C88C923-3D7A-4492-9241-7A489750CAB7} = {B705537C-B82C-4A30-AFA5-6244D9A7DAEB} {8238A052-D626-49EB-A011-51DC6D0DBA30} = {ED0C35EB-7F31-4841-A24F-8EB708FFA959} + {545A88D3-1AE2-4D39-9B7C-C691768AD17F} = {6CE2F530-582B-4695-A209-41065E103426} + {57A61A09-10AD-44BE-8DF4-A6FD108F7DF7} = {6CE2F530-582B-4695-A209-41065E103426} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {0541B30C-FF51-4E28-B172-83F5F3934BCD} diff --git a/playground/MSTest1/MSTest1.csproj b/playground/MSTest1/MSTest1.csproj new file mode 100644 index 0000000000..e952c0fa11 --- /dev/null +++ b/playground/MSTest1/MSTest1.csproj @@ -0,0 +1,30 @@ + + + ..\..\ + true + + + + + $(TargetFrameworks);net472 + + $(TargetFrameworks);net451 + false + + + + + + + + + + + + + + + + + + diff --git a/playground/MSTest1/UnitTest1.cs b/playground/MSTest1/UnitTest1.cs new file mode 100644 index 0000000000..3c93d8ebca --- /dev/null +++ b/playground/MSTest1/UnitTest1.cs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace MSTest1 +{ + [TestClass] + public class UnitTest1 + { + [TestMethod] + public void TestMethod1() + { + } + } +} \ No newline at end of file diff --git a/playground/README.md b/playground/README.md new file mode 100644 index 0000000000..c774287f37 --- /dev/null +++ b/playground/README.md @@ -0,0 +1,17 @@ +# Playground + +This Plaground directory contains projects to aid interactive debugging of test platform. TestPlatform is normally built +as a set of distinct pieces and then assembled in the artifacts folder. This forces rebuilding using build.cmd to try out +changes. The TestPlatform.Playground project builds a simpler version of TestPlatform to avoid always rebuilding via +build.cmd, offering a tighther development loop. + +The project references TranslationLayer, vstest.console, TestHostProvider, testhost and MSTest1 projects, to make sure +we build all the dependencies of that are used to run tests via VSTestConsoleWrapper. It then copies the components from +their original build locations, to $(TargetDir)\vstest.console directory, and it's subfolders to create an executable +copy of TestPlatform that is similar to what we ship. + +The copying might trigger only on re-build, if you see outdated dependencies, Rebuild this project instead of just Build. + +Use this as playground for your debugging of end-to-end scenarios, it will automatically attach vstest.console and teshost +sub-processes. It won't stop at entry-point automatically, don't forget to set your breakpoints, or remove VSTEST_DEBUG_NOBP +from the environment variables of this project. \ No newline at end of file diff --git a/playground/TestPlatform.Playground/Program.cs b/playground/TestPlatform.Playground/Program.cs new file mode 100644 index 0000000000..52a745a7d6 --- /dev/null +++ b/playground/TestPlatform.Playground/Program.cs @@ -0,0 +1,131 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.TestPlatform.VsTestConsole.TranslationLayer; +using Microsoft.VisualStudio.TestPlatform.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Interfaces; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading; + +namespace TestPlatform.Playground +{ + internal class Program + { + static void Main(string[] args) + { + // This project references TranslationLayer, vstest.console, TestHostProvider, testhost and MSTest1 projects, to make sure + // we build all the dependencies of that are used to run tests via VSTestConsoleWrapper. It then copies the components from + // their original build locations, to $(TargetDir)\vstest.console directory, and it's subfolders to create an executable + // copy of TestPlatform that is similar to what we ship. + // + // The copying might trigger only on re-build, if you see outdated dependencies, Rebuild this project instead of just Build. + // + // Use this as playground for your debugging of end-to-end scenarios, it will automatically attach vstest.console and teshost + // sub-processes. It won't stop at entry-point automatically, don't forget to set your breakpoints, or remove VSTEST_DEBUG_NOBP + // from the environment variables of this project. + + var thisAssemblyPath = Assembly.GetEntryAssembly().Location; + var here = Path.GetDirectoryName(thisAssemblyPath); + var playground = Path.GetFullPath(Path.Combine(here, "..", "..", "..", "..")); + + var console = Path.Combine(here, "vstest.console", "vstest.console.exe"); + var consoleOptions = new ConsoleParameters + { + LogFilePath = Path.Combine(here, "logs", "log.txt"), + TraceLevel = TraceLevel.Verbose, + }; + + var r = new VsTestConsoleWrapper(console, consoleOptions); + + var sourceSettings = @" + + + true + + + "; + var sources = new[] { + Path.Combine(playground, "MSTest1", "bin", "Debug", "net472", "MSTest1.dll") + }; + + var options = new TestPlatformOptions(); + r.RunTestsWithCustomTestHost(sources, sourceSettings, options, new TestRunHandler(), new DebuggerTestHostLauncher()); + } + + public class TestRunHandler : ITestRunEventsHandler + { + + public TestRunHandler() + { + } + + public void HandleLogMessage(TestMessageLevel level, string message) + { + Console.WriteLine($"[{level.ToString().ToUpper()}]: {message}"); + } + + public void HandleRawMessage(string rawMessage) + { + Console.WriteLine($"[MESSAGE]: { rawMessage}"); + } + + public void HandleTestRunComplete(TestRunCompleteEventArgs testRunCompleteArgs, TestRunChangedEventArgs lastChunkArgs, ICollection runContextAttachments, ICollection executorUris) + { + Console.WriteLine($"[COMPLETE]: err: { testRunCompleteArgs.Error }, lastChunk: {WriteTests(lastChunkArgs?.NewTestResults)}"); + } + + public void HandleTestRunStatsChange(TestRunChangedEventArgs testRunChangedArgs) + { + Console.WriteLine($"[PROGRESS - NEW RESULTS]: {WriteTests(testRunChangedArgs.NewTestResults)}"); + } + + public int LaunchProcessWithDebuggerAttached(TestProcessStartInfo testProcessStartInfo) + { + throw new NotImplementedException(); + } + + private string WriteTests(IEnumerable testResults) + { + return WriteTests(testResults?.Select(t => t.TestCase)); + } + + private string WriteTests(IEnumerable testCases) + { + return testCases == null ? null : "\t" + string.Join("\n\t", testCases.Select(r => r.DisplayName)); + } + } + + internal class DebuggerTestHostLauncher : ITestHostLauncher2 + { + public bool IsDebug => true; + + public bool AttachDebuggerToProcess(int pid) + { + return true; + } + + public bool AttachDebuggerToProcess(int pid, CancellationToken cancellationToken) + { + return true; + } + + public int LaunchTestHost(TestProcessStartInfo defaultTestHostStartInfo) + { + return 1; + } + + public int LaunchTestHost(TestProcessStartInfo defaultTestHostStartInfo, CancellationToken cancellationToken) + { + return 1; + } + } + } +} \ No newline at end of file diff --git a/playground/TestPlatform.Playground/Properties/launchSettings.json b/playground/TestPlatform.Playground/Properties/launchSettings.json new file mode 100644 index 0000000000..c688670d9c --- /dev/null +++ b/playground/TestPlatform.Playground/Properties/launchSettings.json @@ -0,0 +1,14 @@ +{ + "profiles": { + "TestPlatform.Playground": { + "commandName": "Project", + "environmentVariables": { + "VSTEST_CONNECTION_TIMEOUT": "999", + "VSTEST_DEBUG_NOBP": "1", + "VSTEST_RUNNER_DEBUG_ATTACHVS": "1", + "VSTEST_HOST_DEBUG_ATTACHVS": "1", + "VSTEST_DATACOLLECTOR_DEBUG_ATTACHVS": "1" + } + } + } +} diff --git a/playground/TestPlatform.Playground/TestPlatform.Playground.csproj b/playground/TestPlatform.Playground/TestPlatform.Playground.csproj new file mode 100644 index 0000000000..d73746f16e --- /dev/null +++ b/playground/TestPlatform.Playground/TestPlatform.Playground.csproj @@ -0,0 +1,45 @@ + + + ..\..\ + true + + + $(MSBuildWarningsAsMessages);MSB3270;MSB3276 + + + + + Exe + $(TargetFrameworks);net472 + + $(TargetFrameworks);net451 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From fff6266c87f1a771b5b130dd90133c05f14a93d8 Mon Sep 17 00:00:00 2001 From: Medeni Baykal <433724+Haplois@users.noreply.github.com> Date: Tue, 15 Feb 2022 23:22:32 +0100 Subject: [PATCH 2/2] Added support for TestAdapterLoadingStrategy. --- .../TestPlatform.cs | 237 ++++++++++------ .../TestExtensionManager.cs | 1 - .../Utilities/RunSettingsUtilities.cs | 12 +- .../Friends.cs | 2 + .../RunSettings/RunConfiguration.cs | 26 ++ .../TestAdapterLoadingStrategy.cs | 47 ++++ .../CommandLine/CommandLineOptions.cs | 9 +- src/vstest.console/CommandLine/Executor.cs | 9 +- .../RunSpecificTestsArgumentProcessor.cs | 4 +- .../Processors/RunTestsArgumentProcessor.cs | 2 +- ...AdapterLoadingStrategyArgumentProcessor.cs | 256 ++++++++++++++++++ .../TestAdapterPathArgumentProcessor.cs | 59 ++-- .../Utilities/ArgumentProcessorFactory.cs | 8 +- .../Utilities/ArgumentProcessorPriority.cs | 10 +- .../Utilities/HelpContentPriority.cs | 8 +- .../Resources/Resources.Designer.cs | 42 +++ src/vstest.console/Resources/Resources.resx | 38 +++ .../Resources/xlf/Resources.cs.xlf | 54 ++++ .../Resources/xlf/Resources.de.xlf | 54 ++++ .../Resources/xlf/Resources.es.xlf | 54 ++++ .../Resources/xlf/Resources.fr.xlf | 54 ++++ .../Resources/xlf/Resources.it.xlf | 54 ++++ .../Resources/xlf/Resources.ja.xlf | 54 ++++ .../Resources/xlf/Resources.ko.xlf | 54 ++++ .../Resources/xlf/Resources.pl.xlf | 54 ++++ .../Resources/xlf/Resources.pt-BR.xlf | 54 ++++ .../Resources/xlf/Resources.ru.xlf | 54 ++++ .../Resources/xlf/Resources.tr.xlf | 54 ++++ .../Resources/xlf/Resources.xlf | 54 ++++ .../Resources/xlf/Resources.zh-Hans.xlf | 54 ++++ .../Resources/xlf/Resources.zh-Hant.xlf | 54 ++++ .../RunSpecificTestsArgumentProcessorTests.cs | 2 +- ...erLoadingStrategyArgumentProcessorTests.cs | 133 +++++++++ .../TestAdapterPathArgumentProcessorTests.cs | 86 ------ 34 files changed, 1527 insertions(+), 220 deletions(-) create mode 100644 src/Microsoft.TestPlatform.ObjectModel/TestAdapterLoadingStrategy.cs create mode 100644 src/vstest.console/Processors/TestAdapterLoadingStrategyArgumentProcessor.cs create mode 100644 test/vstest.console.UnitTests/Processors/TestAdapterLoadingStrategyArgumentProcessorTests.cs diff --git a/src/Microsoft.TestPlatform.Client/TestPlatform.cs b/src/Microsoft.TestPlatform.Client/TestPlatform.cs index bb7c62320d..5a2c928315 100644 --- a/src/Microsoft.TestPlatform.Client/TestPlatform.cs +++ b/src/Microsoft.TestPlatform.Client/TestPlatform.cs @@ -26,6 +26,7 @@ namespace Microsoft.VisualStudio.TestPlatform.Client using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions; using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers; using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces; + using ClientResources = Resources.Resources; /// @@ -89,15 +90,7 @@ public IDiscoveryRequest CreateDiscoveryRequest( throw new ArgumentNullException(nameof(discoveryCriteria)); } - // Update cache with Extension folder's files. - this.AddExtensionAssemblies(discoveryCriteria.RunSettings); - - // Update extension assemblies from source when design mode is false. - var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(discoveryCriteria.RunSettings); - if (!runConfiguration.DesignMode) - { - this.AddExtensionAssembliesFromSource(discoveryCriteria.Sources); - } + PopulateExtensions(discoveryCriteria.RunSettings, discoveryCriteria.Sources); // Initialize loggers. var loggerManager = this.TestEngine.GetLoggerManager(requestData); @@ -125,15 +118,8 @@ public ITestRunRequest CreateTestRunRequest( throw new ArgumentNullException(nameof(testRunCriteria)); } - this.AddExtensionAssemblies(testRunCriteria.TestRunSettings); - - var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(testRunCriteria.TestRunSettings); - - // Update extension assemblies from source when design mode is false. - if (!runConfiguration.DesignMode) - { - this.AddExtensionAssembliesFromSource(testRunCriteria); - } + var sources = GetSources(testRunCriteria); + PopulateExtensions(testRunCriteria.TestRunSettings, sources); // Initialize loggers. var loggerManager = this.TestEngine.GetLoggerManager(requestData); @@ -156,6 +142,21 @@ public ITestRunRequest CreateTestRunRequest( return new TestRunRequest(requestData, testRunCriteria, executionManager, loggerManager); } + private void PopulateExtensions(string runSettings, IEnumerable sources) + { + var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(runSettings); + var strategy = runConfiguration.TestAdapterLoadingStrategy; + + // Update cache with Extension folder's files. + this.AddExtensionAssemblies(runSettings, strategy); + + // Update extension assemblies from source when design mode is false. + if (!runConfiguration.DesignMode) + { + this.AddExtensionAssembliesFromSource(sources, strategy); + } + } + /// public bool StartTestSession( IRequestData requestData, @@ -167,9 +168,11 @@ public bool StartTestSession( throw new ArgumentNullException(nameof(testSessionCriteria)); } - this.AddExtensionAssemblies(testSessionCriteria.RunSettings); - var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(testSessionCriteria.RunSettings); + var strategy = runConfiguration.TestAdapterLoadingStrategy; + + this.AddExtensionAssemblies(testSessionCriteria.RunSettings, strategy); + if (!runConfiguration.DesignMode) { return false; @@ -222,13 +225,7 @@ private void ThrowExceptionIfTestHostManagerIsNull( } } - /// - /// Updates the test adapter paths provided through run settings to be used by the test - /// service. - /// - /// - /// The run settings. - private void AddExtensionAssemblies(string runSettings) + private void AddExtensionAssemblies(string runSettings, TestAdapterLoadingStrategy adapterLoadingStrategy) { IEnumerable customTestAdaptersPaths = RunSettingsUtilities.GetTestAdaptersPaths(runSettings); @@ -236,71 +233,45 @@ private void AddExtensionAssemblies(string runSettings) { foreach (string customTestAdaptersPath in customTestAdaptersPaths) { - var adapterPath = Path.GetFullPath(Environment.ExpandEnvironmentVariables(customTestAdaptersPath)); - if (!Directory.Exists(adapterPath)) - { - if (EqtTrace.IsWarningEnabled) - { - EqtTrace.Warning(string.Format("AdapterPath Not Found:", adapterPath)); - } + var extensionAssemblies = ExpandTestAdapterPaths(customTestAdaptersPath, this.fileHelper, adapterLoadingStrategy); - continue; - } - - var extensionAssemblies = new List( - this.fileHelper.EnumerateFiles( - adapterPath, - SearchOption.AllDirectories, - TestPlatformConstants.TestAdapterEndsWithPattern, - TestPlatformConstants.TestLoggerEndsWithPattern, - TestPlatformConstants.DataCollectorEndsWithPattern, - TestPlatformConstants.RunTimeEndsWithPattern)); - - if (extensionAssemblies.Count > 0) + if (extensionAssemblies.Any()) { this.UpdateExtensions(extensionAssemblies, skipExtensionFilters: false); } + } } } /// - /// Updates the extension assemblies from source directory. + /// Updates the test logger paths from source directory. /// /// - /// The test run criteria. - private void AddExtensionAssembliesFromSource(TestRunCriteria testRunCriteria) + /// The list of sources. + private void AddExtensionAssembliesFromSource(IEnumerable sources, TestAdapterLoadingStrategy strategy) { - IEnumerable sources = testRunCriteria.Sources; - if (testRunCriteria.HasSpecificTests) + // Skip discovery unless we're using the default behavior, or NextToSource is specified. + if (strategy != TestAdapterLoadingStrategy.Default + && (strategy & TestAdapterLoadingStrategy.NextToSource) != TestAdapterLoadingStrategy.NextToSource) { - // If the test execution is with a test filter, group them by sources. - sources = testRunCriteria.Tests.Select(tc => tc.Source).Distinct(); + return; } - AddExtensionAssembliesFromSource(sources); - } - - /// - /// Updates the test logger paths from source directory. - /// - /// - /// The list of sources. - private void AddExtensionAssembliesFromSource(IEnumerable sources) - { // Currently we support discovering loggers only from Source directory. var loggersToUpdate = new List(); foreach (var source in sources) { var sourceDirectory = Path.GetDirectoryName(source); - if (!string.IsNullOrEmpty(sourceDirectory) - && this.fileHelper.DirectoryExists(sourceDirectory)) + if (!string.IsNullOrEmpty(sourceDirectory) && this.fileHelper.DirectoryExists(sourceDirectory)) { + var searchOption = GetSearchOption(strategy, SearchOption.TopDirectoryOnly); + loggersToUpdate.AddRange( this.fileHelper.EnumerateFiles( sourceDirectory, - SearchOption.TopDirectoryOnly, + searchOption, TestPlatformConstants.TestLoggerEndsWithPattern)); } } @@ -318,22 +289,134 @@ private void AddExtensionAssembliesFromSource(IEnumerable sources) /// private static void AddExtensionAssembliesFromExtensionDirectory() { + // This method runs before adapter initialization path, ideally we should replace this mechanism + // this is currently required because we need TestHostProvider to be able to resolve. + var runSettings = RunSettingsManager.Instance.ActiveRunSettings.SettingsXml; + var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(runSettings); + var strategy = runConfiguration.TestAdapterLoadingStrategy; + var fileHelper = new FileHelper(); - var extensionsFolder = Path.Combine( - Path.GetDirectoryName( - typeof(TestPlatform).GetTypeInfo().Assembly.GetAssemblyLocation()), - "Extensions"); + var defaultExtensionPaths = Enumerable.Empty(); + // Explicit adapter loading + if ((strategy & TestAdapterLoadingStrategy.Explicit) == TestAdapterLoadingStrategy.Explicit) + { + defaultExtensionPaths = RunSettingsUtilities.GetTestAdaptersPaths(runSettings) + .SelectMany(path => ExpandTestAdapterPaths(path, fileHelper, strategy)) + .Union(defaultExtensionPaths); + } + + var extensionsFolder = Path.Combine(Path.GetDirectoryName(typeof(TestPlatform).GetTypeInfo().Assembly.GetAssemblyLocation()), "Extensions"); if (fileHelper.DirectoryExists(extensionsFolder)) { - var defaultExtensionPaths = fileHelper.EnumerateFiles( - extensionsFolder, - SearchOption.TopDirectoryOnly, - ".dll", - ".exe"); + // Load default runtime providers + if ((strategy & TestAdapterLoadingStrategy.DefaultRuntimeProviders) == TestAdapterLoadingStrategy.DefaultRuntimeProviders) + { + defaultExtensionPaths = fileHelper + .EnumerateFiles(extensionsFolder, SearchOption.TopDirectoryOnly, TestPlatformConstants.RunTimeEndsWithPattern) + .Union(defaultExtensionPaths); + } + + // Default extension loader + if (strategy == TestAdapterLoadingStrategy.Default + || (strategy & TestAdapterLoadingStrategy.ExtensionsDirectory) == TestAdapterLoadingStrategy.ExtensionsDirectory) + { + defaultExtensionPaths = fileHelper + .EnumerateFiles(extensionsFolder, SearchOption.TopDirectoryOnly, ".dll", ".exe") + .Union(defaultExtensionPaths); + } + } + + TestPluginCache.Instance.DefaultExtensionPaths = defaultExtensionPaths.Distinct(); + } + + private static SearchOption GetSearchOption(TestAdapterLoadingStrategy strategy, SearchOption defaultStrategyOption) { + if (strategy == TestAdapterLoadingStrategy.Default) { + return defaultStrategyOption; + } + + var searchOption = SearchOption.TopDirectoryOnly; + if ((strategy & TestAdapterLoadingStrategy.Recursive) == TestAdapterLoadingStrategy.Recursive) + { + searchOption = SearchOption.AllDirectories; + } + + return searchOption; + } - TestPluginCache.Instance.DefaultExtensionPaths = defaultExtensionPaths; + private static IEnumerable ExpandTestAdapterPaths(string path, IFileHelper fileHelper, TestAdapterLoadingStrategy strategy) + { + var adapterPath = Path.GetFullPath(Environment.ExpandEnvironmentVariables(path)); + + // Default behavior is to only accept directories! + if (strategy == TestAdapterLoadingStrategy.Default) + { + return ExpandAdaptersWithDefaultStrategy(adapterPath, fileHelper); + } + + var adapters = ExpandAdaptersWithExplicitStrategy(adapterPath, fileHelper, strategy); + + return adapters.Distinct(); + } + + private static IEnumerable ExpandAdaptersWithExplicitStrategy(string path, IFileHelper fileHelper, TestAdapterLoadingStrategy strategy) + { + if ((strategy & TestAdapterLoadingStrategy.Explicit) != TestAdapterLoadingStrategy.Explicit) + { + return Enumerable.Empty(); } + + if (fileHelper.Exists(path)) + { + return new[] { path }; + } + else if (fileHelper.DirectoryExists(path)) + { + var searchOption = GetSearchOption(strategy, SearchOption.TopDirectoryOnly); + + var adapterPaths = fileHelper.EnumerateFiles( + path, + searchOption, + TestPlatformConstants.TestAdapterEndsWithPattern, + TestPlatformConstants.TestLoggerEndsWithPattern, + TestPlatformConstants.DataCollectorEndsWithPattern, + TestPlatformConstants.RunTimeEndsWithPattern); + + return adapterPaths; + } + + EqtTrace.Warning(string.Format("AdapterPath Not Found:", path)); + return Enumerable.Empty(); + } + + private static IEnumerable ExpandAdaptersWithDefaultStrategy(string path, IFileHelper fileHelper) + { + if (!fileHelper.DirectoryExists(path)) + { + EqtTrace.Warning(string.Format("AdapterPath Not Found:", path)); + + return Enumerable.Empty(); + } + + return fileHelper.EnumerateFiles( + path, + SearchOption.AllDirectories, + TestPlatformConstants.TestAdapterEndsWithPattern, + TestPlatformConstants.TestLoggerEndsWithPattern, + TestPlatformConstants.DataCollectorEndsWithPattern, + TestPlatformConstants.RunTimeEndsWithPattern); + } + + private static IEnumerable GetSources(TestRunCriteria testRunCriteria) + { + IEnumerable sources = testRunCriteria.Sources; + if (testRunCriteria.HasSpecificTests) + { + // If the test execution is with a test filter, group them by sources. + sources = testRunCriteria.Tests.Select(tc => tc.Source).Distinct(); + } + + return sources; } } } diff --git a/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestExtensionManager.cs b/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestExtensionManager.cs index 7bf7bb2d74..133409c6b8 100644 --- a/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestExtensionManager.cs +++ b/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestExtensionManager.cs @@ -126,7 +126,6 @@ public LazyExtension TryGetTestExtension(Uri extensionUri /// /// The URI of the test extension to be looked up. /// The test extension or null if one was not found. - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1057:StringUriOverloadsCallSystemUriOverloads", Justification = "Case insensitiveness needs to be supported.")] public LazyExtension TryGetTestExtension(string extensionUri) { ValidateArg.NotNull(extensionUri, nameof(extensionUri)); diff --git a/src/Microsoft.TestPlatform.Common/Utilities/RunSettingsUtilities.cs b/src/Microsoft.TestPlatform.Common/Utilities/RunSettingsUtilities.cs index 28f037c4c9..9d8fe81ec8 100644 --- a/src/Microsoft.TestPlatform.Common/Utilities/RunSettingsUtilities.cs +++ b/src/Microsoft.TestPlatform.Common/Utilities/RunSettingsUtilities.cs @@ -175,7 +175,6 @@ private static bool GetTreatNoTestsAsError(RunConfiguration runConfiguration) /// Gets the test adapters path from the run configuration /// /// Test run settings - /// True to return null, if adapter paths is not set. /// Test adapters paths public static IEnumerable GetTestAdaptersPaths(string runSettings) { @@ -193,5 +192,16 @@ public static IEnumerable GetTestAdaptersPaths(string runSettings) return testAdaptersPaths; } + /// + /// Gets the test adapter loading strategy + /// + /// Test run settings + /// Test adapter loading strategy + internal static TestAdapterLoadingStrategy GetLoadingStrategy(string runSettings) { + var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(runSettings); + + return runConfiguration?.TestAdapterLoadingStrategy ?? TestAdapterLoadingStrategy.Default; + } + } } diff --git a/src/Microsoft.TestPlatform.ObjectModel/Friends.cs b/src/Microsoft.TestPlatform.ObjectModel/Friends.cs index 7e2123cd6d..63d5c25c54 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Friends.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/Friends.cs @@ -8,6 +8,8 @@ [assembly: InternalsVisibleTo("Microsoft.VisualStudio.TestPlatform.Extensions.MSPhoneAdapter, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] [assembly: InternalsVisibleTo("datacollector, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] [assembly: InternalsVisibleTo("Microsoft.VisualStudio.TestPlatform.Common, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] +[assembly: InternalsVisibleTo("vstest.console, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] +[assembly: InternalsVisibleTo("Microsoft.VisualStudio.TestPlatform.Client, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] [assembly: InternalsVisibleTo("Microsoft.TestPlatform.ObjectModel.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] [assembly: InternalsVisibleTo("datacollector.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] diff --git a/src/Microsoft.TestPlatform.ObjectModel/RunSettings/RunConfiguration.cs b/src/Microsoft.TestPlatform.ObjectModel/RunSettings/RunConfiguration.cs index bee3c87e8d..66dc0916d2 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/RunSettings/RunConfiguration.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/RunSettings/RunConfiguration.cs @@ -385,6 +385,11 @@ public string TestAdaptersPaths } } + /// + /// Gets or sets the test adapter loading strategy. + /// + internal TestAdapterLoadingStrategy TestAdapterLoadingStrategy { get; set; } + /// /// Gets or sets the execution thread apartment state. /// @@ -571,6 +576,13 @@ public override XmlElement ToXml() root.AppendChild(testAdaptersPaths); } + if(this.TestAdapterLoadingStrategy != TestAdapterLoadingStrategy.Default) + { + XmlElement adapterLoadingStrategy = doc.CreateElement("TestAdapterLoadingStrategy"); + adapterLoadingStrategy.InnerXml = this.TestAdapterLoadingStrategy.ToString(); + root.AppendChild(adapterLoadingStrategy); + } + XmlElement treatTestAdapterErrorsAsWarnings = doc.CreateElement("TreatTestAdapterErrorsAsWarnings"); treatTestAdapterErrorsAsWarnings.InnerXml = this.TreatTestAdapterErrorsAsWarnings.ToString(); root.AppendChild(treatTestAdapterErrorsAsWarnings); @@ -838,6 +850,19 @@ public static RunConfiguration FromXml(XmlReader reader) runConfiguration.TestAdaptersPaths = reader.ReadElementContentAsString(); break; + case "TestAdapterLoadingStrategy": + XmlRunSettingsUtilities.ThrowOnHasAttributes(reader); + value = reader.ReadElementContentAsString(); + if (Enum.TryParse(value, out var loadingStrategy)) { + runConfiguration.TestAdapterLoadingStrategy = loadingStrategy; + } + else { + throw new SettingsException(string.Format(CultureInfo.CurrentCulture, + Resources.Resources.InvalidSettingsIncorrectValue, Constants.RunConfigurationSettingsName, value, elementName)); + } + + break; + case "TreatTestAdapterErrorsAsWarnings": XmlRunSettingsUtilities.ThrowOnHasAttributes(reader); bool treatTestAdapterErrorsAsWarnings = false; @@ -925,6 +950,7 @@ public static RunConfiguration FromXml(XmlReader reader) XmlRunSettingsUtilities.ThrowOnHasAttributes(reader); runConfiguration.DotnetHostPath = reader.ReadElementContentAsString(); break; + case "TreatNoTestsAsError": XmlRunSettingsUtilities.ThrowOnHasAttributes(reader); string treatNoTestsAsErrorValueString = reader.ReadElementContentAsString(); diff --git a/src/Microsoft.TestPlatform.ObjectModel/TestAdapterLoadingStrategy.cs b/src/Microsoft.TestPlatform.ObjectModel/TestAdapterLoadingStrategy.cs new file mode 100644 index 0000000000..a99a6ac105 --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/TestAdapterLoadingStrategy.cs @@ -0,0 +1,47 @@ +// 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; + +namespace Microsoft.VisualStudio.TestPlatform.ObjectModel +{ + /// + /// Represents a loading strategy + /// + [Flags] + internal enum TestAdapterLoadingStrategy + { + /// + /// A strategy not defined, Test Platfrom will load adapters normally. + /// + Default = 0b0000_0000_0000_0000, + + /// + /// Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + /// If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded. + /// If no adapter path is specified, test run will fail. + /// This will imply /InIsolation switch and force the tests to be run in an isolated process. + /// + Explicit = 0b0000_0000_0000_0001, + + /// + /// Load adapters next to source. + /// + NextToSource = 0b0000_0000_0000_0010, + + /// + /// Default runtime providers inside Extensions folder will be included + /// + DefaultRuntimeProviders = 0b0000_0000_0000_0100, + + /// + /// Load adapters inside Extensions folder. + /// + ExtensionsDirectory = 0b0000_0000_0000_1000, + + /// + /// Directory wide searches will be recursive, this is required to be with with NextToSource or Explicit. + /// + Recursive = 0b0001_0000_0000_0000, + } +} diff --git a/src/vstest.console/CommandLine/CommandLineOptions.cs b/src/vstest.console/CommandLine/CommandLineOptions.cs index 4edd13929b..923b7b8127 100644 --- a/src/vstest.console/CommandLine/CommandLineOptions.cs +++ b/src/vstest.console/CommandLine/CommandLineOptions.cs @@ -132,7 +132,12 @@ public IEnumerable Sources /// /// Path to the custom test adapters. /// - public string TestAdapterPath { get; set; } + public string[] TestAdapterPath { get; set; } + + /// + /// Test adapter loading strategy. + /// + public TestAdapterLoadingStrategy TestAdapterLoadingStrategy { get; set; } /// /// Process Id of the process which launched vstest runner @@ -304,6 +309,8 @@ public void AddSource(string source) this.sources = this.sources.Union(matchingFiles).ToList(); } + public bool TestAdapterPathsSet => (TestAdapterPath?.Length ?? 0) != 0; + #endregion #region Internal Methods diff --git a/src/vstest.console/CommandLine/Executor.cs b/src/vstest.console/CommandLine/Executor.cs index 4357c0af3a..7c0e9d0045 100644 --- a/src/vstest.console/CommandLine/Executor.cs +++ b/src/vstest.console/CommandLine/Executor.cs @@ -210,7 +210,14 @@ private int GetArgumentProcessors(string[] args, out List pr // Examples: processors to enable loggers that are statically configured, and to start logging, // should always be executed. var processorsToAlwaysExecute = processorFactory.GetArgumentProcessorsToAlwaysExecute(); - processors.AddRange(processorsToAlwaysExecute); + foreach (var processor in processorsToAlwaysExecute) + { + if (processors.Any(i => i.Metadata.Value.CommandName == processor.Metadata.Value.CommandName)) { + continue; + } + + processors.Add(ArgumentProcessorFactory.WrapLazyProcessorToInitializeOnInstantiation(processor)); + } // Initialize Runsettings with defaults RunSettingsManager.Instance.AddDefaultRunSettings(); diff --git a/src/vstest.console/Processors/RunSpecificTestsArgumentProcessor.cs b/src/vstest.console/Processors/RunSpecificTestsArgumentProcessor.cs index 96e3e44223..1916b86b47 100644 --- a/src/vstest.console/Processors/RunSpecificTestsArgumentProcessor.cs +++ b/src/vstest.console/Processors/RunSpecificTestsArgumentProcessor.cs @@ -283,7 +283,7 @@ private void ExecuteSelectedTests() // No tests were discovered from the given sources. warningMessage = string.Format(CultureInfo.CurrentUICulture, CommandLineResources.NoTestsAvailableInSources, string.Join(", ", this.commandLineOptions.Sources)); - if (string.IsNullOrEmpty(this.commandLineOptions.TestAdapterPath)) + if (!commandLineOptions.TestAdapterPathsSet) { warningMessage = string.Format(CultureInfo.CurrentCulture, CommandLineResources.StringFormatToJoinTwoStrings, warningMessage, CommandLineResources.SuggestTestAdapterPathIfNoTestsIsFound); } @@ -385,7 +385,7 @@ private void TestRunRequest_OnRunCompletion(object sender, TestRunCompleteEventA var testsFoundInAnySource = (e.TestRunStatistics == null) ? false : (e.TestRunStatistics.ExecutedTests > 0); // Indicate the user to use testadapterpath command if there are no tests found - if (!testsFoundInAnySource && string.IsNullOrEmpty(CommandLineOptions.Instance.TestAdapterPath) && this.commandLineOptions.TestCaseFilterValue == null) + if (!testsFoundInAnySource && !CommandLineOptions.Instance.TestAdapterPathsSet && this.commandLineOptions.TestCaseFilterValue == null) { this.output.Warning(false, CommandLineResources.SuggestTestAdapterPathIfNoTestsIsFound); } diff --git a/src/vstest.console/Processors/RunTestsArgumentProcessor.cs b/src/vstest.console/Processors/RunTestsArgumentProcessor.cs index 4e624019f2..a52c8e9619 100644 --- a/src/vstest.console/Processors/RunTestsArgumentProcessor.cs +++ b/src/vstest.console/Processors/RunTestsArgumentProcessor.cs @@ -257,7 +257,7 @@ private void TestRunRequest_OnRunCompletion(object sender, TestRunCompleteEventA var testsFoundInAnySource = (e.TestRunStatistics == null) ? false : (e.TestRunStatistics.ExecutedTests > 0); // Indicate the user to use test adapter path command if there are no tests found - if (!testsFoundInAnySource && string.IsNullOrEmpty(CommandLineOptions.Instance.TestAdapterPath) && this.commandLineOptions.TestCaseFilterValue == null) + if (!testsFoundInAnySource && !CommandLineOptions.Instance.TestAdapterPathsSet && this.commandLineOptions.TestCaseFilterValue == null) { this.output.Warning(false, CommandLineResources.SuggestTestAdapterPathIfNoTestsIsFound); } diff --git a/src/vstest.console/Processors/TestAdapterLoadingStrategyArgumentProcessor.cs b/src/vstest.console/Processors/TestAdapterLoadingStrategyArgumentProcessor.cs new file mode 100644 index 0000000000..f265584dd1 --- /dev/null +++ b/src/vstest.console/Processors/TestAdapterLoadingStrategyArgumentProcessor.cs @@ -0,0 +1,256 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestPlatform.CommandLine.Processors +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.Contracts; + using System.Globalization; + using System.IO; + using System.Linq; + + using Microsoft.VisualStudio.TestPlatform.Common; + using Microsoft.VisualStudio.TestPlatform.Common.Interfaces; + using Microsoft.VisualStudio.TestPlatform.Common.Utilities; + using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using Microsoft.VisualStudio.TestPlatform.Utilities; + using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers; + using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces; + + using CommandLineResources = Microsoft.VisualStudio.TestPlatform.CommandLine.Resources.Resources; + + /// + /// Allows the user to specify a order of loading custom adapters from. + /// + internal class TestAdapterLoadingStrategyArgumentProcessor : IArgumentProcessor + { + #region Constants + + /// + /// The name of the command line argument that the TestAdapterLoadingStrategyArgumentProcessor handles. + /// + public const string CommandName = "/TestAdapterLoadingStrategy"; + + #endregion + + private Lazy metadata; + + private Lazy executor; + + /// + /// Gets the metadata. + /// + public Lazy Metadata + { + get + { + if (this.metadata == null) + { + this.metadata = new Lazy(() => new TestAdapterLoadingStrategyArgumentProcessorCapabilities()); + } + + return this.metadata; + } + } + + /// + /// Gets or sets the executor. + /// + public Lazy Executor + { + get + { + if (this.executor == null) + { + this.executor = new Lazy(() => new TestAdapterLoadingStrategyArgumentExecutor(CommandLineOptions.Instance, RunSettingsManager.Instance, ConsoleOutput.Instance, new FileHelper())); + } + + return this.executor; + } + + set + { + this.executor = value; + } + } + } + + /// + /// The argument capabilities. + /// + internal class TestAdapterLoadingStrategyArgumentProcessorCapabilities : BaseArgumentProcessorCapabilities + { + public override string CommandName => TestAdapterLoadingStrategyArgumentProcessor.CommandName; + + public override bool AllowMultiple => false; + + public override bool IsAction => false; + + public override bool AlwaysExecute => true; + + public override ArgumentProcessorPriority Priority => ArgumentProcessorPriority.TestAdapterLoadingStrategy; + + public override string HelpContentResourceName => CommandLineResources.TestAdapterLoadingStrategyHelp; + + public override HelpContentPriority HelpPriority => HelpContentPriority.TestAdapterLoadingStrategyArgumentProcessorHelpPriority; + } + + /// + /// The argument executor. + /// + internal class TestAdapterLoadingStrategyArgumentExecutor : IArgumentExecutor + { + #region Fields + /// + /// Used for getting sources. + /// + private CommandLineOptions commandLineOptions; + + /// + /// Run settings provider. + /// + private IRunSettingsProvider runSettingsManager; + + /// + /// Used for sending output. + /// + private IOutput output; + + /// + /// For file related operation + /// + private IFileHelper fileHelper; + + #endregion + + public const string DefaultStrategy = "Default"; + public const string ExplicitStrategy = "Explicit"; + + /// + /// Default constructor. + /// + /// The options. + /// The test platform + public TestAdapterLoadingStrategyArgumentExecutor(CommandLineOptions options, IRunSettingsProvider runSettingsManager, IOutput output, IFileHelper fileHelper) + { + Contract.Requires(options != null); + + this.commandLineOptions = options; + this.runSettingsManager = runSettingsManager; + this.output = output; + this.fileHelper = fileHelper; + } + + #region IArgumentExecutor + + /// + /// Initializes with the argument that was provided with the command. + /// + /// Argument that was provided with the command. + public void Initialize(string argument) + { + var strategy = TestAdapterLoadingStrategy.Default; + + if (!string.IsNullOrEmpty(argument) && !Enum.TryParse(argument, out strategy)) + { + throw new CommandLineException(string.Format(CultureInfo.CurrentCulture, CommandLineResources.TestAdapterLoadingStrategyValueInvalid, argument)); + } + + if (strategy == TestAdapterLoadingStrategy.Recursive) { + throw new CommandLineException(string.Format(CultureInfo.CurrentCulture, CommandLineResources.TestAdapterLoadingStrategyValueInvalidRecursive, $"{nameof(TestAdapterLoadingStrategy.Explicit)}, {nameof(TestAdapterLoadingStrategy.NextToSource)}")); + } + + if (string.IsNullOrWhiteSpace(argument)) + { + InitializeDefaultStrategy(); + return; + } + + InitializeStrategy(strategy); + } + + private void InitializeDefaultStrategy() + { + ValidateTestAdapterPaths(TestAdapterLoadingStrategy.Default); + + SetStrategy(TestAdapterLoadingStrategy.Default); + } + + private void InitializeStrategy(TestAdapterLoadingStrategy strategy) + { + ValidateTestAdapterPaths(strategy); + + if (!commandLineOptions.TestAdapterPathsSet && (strategy & TestAdapterLoadingStrategy.Explicit) == TestAdapterLoadingStrategy.Explicit) + { + throw new CommandLineException(string.Format(CultureInfo.CurrentCulture, CommandLineResources.TestAdapterPathValueRequiredWhenStrategyXIsUsed, ExplicitStrategy)); + } + + SetStrategy(strategy); + } + + private void ForceIsolation() + { + if (this.commandLineOptions.InIsolation) + { + return; + } + + this.commandLineOptions.InIsolation = true; + this.runSettingsManager.UpdateRunSettingsNode(InIsolationArgumentExecutor.RunSettingsPath, "true"); + } + + private void ValidateTestAdapterPaths(TestAdapterLoadingStrategy strategy) + { + var testAdapterPaths = commandLineOptions.TestAdapterPath ?? new string[0]; + if (!commandLineOptions.TestAdapterPathsSet) + { + testAdapterPaths = TestAdapterPathArgumentExecutor.SplitPaths(this.runSettingsManager.QueryRunSettingsNode("RunConfiguration.TestAdaptersPaths")).Union(testAdapterPaths).Distinct().ToArray(); + } + + for (var i = 0; i < testAdapterPaths.Length; i++) + { + var adapterPath = testAdapterPaths[i]; + var testAdapterPath = this.fileHelper.GetFullPath(Environment.ExpandEnvironmentVariables(adapterPath)); + + if (strategy == TestAdapterLoadingStrategy.Default) + { + if (!this.fileHelper.DirectoryExists(testAdapterPath)) + { + throw new CommandLineException( + string.Format(CultureInfo.CurrentCulture, CommandLineResources.InvalidTestAdapterPathCommand, adapterPath, CommandLineResources.TestAdapterPathDoesNotExist) + ); + } + } + + testAdapterPaths[i] = testAdapterPath; + } + + this.runSettingsManager.UpdateRunSettingsNode("RunConfiguration.TestAdaptersPaths", string.Join(";", testAdapterPaths)); + } + + private void SetStrategy(TestAdapterLoadingStrategy strategy) + { + var adapterStrategy = strategy.ToString(); + + commandLineOptions.TestAdapterLoadingStrategy = strategy; + this.runSettingsManager.UpdateRunSettingsNode("RunConfiguration.TestAdapterLoadingStrategy", adapterStrategy); + if ((strategy & TestAdapterLoadingStrategy.Explicit) == TestAdapterLoadingStrategy.Explicit) + { + ForceIsolation(); + } + } + + /// + /// Executes the argument processor. + /// + /// The . + public ArgumentProcessorResult Execute() + { + // Nothing to do since we updated the parameter during initialize parameter + return ArgumentProcessorResult.Success; + } + + #endregion + } +} \ No newline at end of file diff --git a/src/vstest.console/Processors/TestAdapterPathArgumentProcessor.cs b/src/vstest.console/Processors/TestAdapterPathArgumentProcessor.cs index 120544e1c8..07fee0fdfe 100644 --- a/src/vstest.console/Processors/TestAdapterPathArgumentProcessor.cs +++ b/src/vstest.console/Processors/TestAdapterPathArgumentProcessor.cs @@ -123,7 +123,7 @@ internal class TestAdapterPathArgumentExecutor : IArgumentExecutor /// /// Separators for multiple paths in argument. /// - private readonly char[] argumentSeparators = new[] { ';' }; + private static readonly char[] argumentSeparators = new[] { ';' }; #endregion @@ -154,60 +154,33 @@ public TestAdapterPathArgumentExecutor(CommandLineOptions options, IRunSettingsP /// Argument that was provided with the command. public void Initialize(string argument) { - string invalidAdapterPathArgument = argument; - if (string.IsNullOrWhiteSpace(argument)) { throw new CommandLineException( string.Format(CultureInfo.CurrentCulture, CommandLineResources.TestAdapterPathValueRequired)); } - string customAdaptersPath; - - try - { - var testAdapterPaths = new List(); - var testAdapterFullPaths = new List(); - - // VSTS task add double quotes around TestAdapterpath. For example if user has given TestAdapter path C:\temp, - // Then VSTS task will add TestAdapterPath as "/TestAdapterPath:\"C:\Temp\"". - // Remove leading and trailing ' " ' chars... - argument = argument.Trim().Trim(new char[] { '\"' }); + string[] customAdaptersPath; - // Get test adapter paths from RunSettings. - var testAdapterPathsInRunSettings = this.runSettingsManager.QueryRunSettingsNode("RunConfiguration.TestAdaptersPaths"); + var testAdapterPaths = new List(); - if (!string.IsNullOrWhiteSpace(testAdapterPathsInRunSettings)) - { - testAdapterPaths.AddRange(SplitPaths(testAdapterPathsInRunSettings)); - } + // VSTS task add double quotes around TestAdapterpath. For example if user has given TestAdapter path C:\temp, + // Then VSTS task will add TestAdapterPath as "/TestAdapterPath:\"C:\Temp\"". + // Remove leading and trailing ' " ' chars... + argument = argument.Trim().Trim(new char[] { '\"' }); - testAdapterPaths.AddRange(SplitPaths(argument)); - - foreach (var testadapterPath in testAdapterPaths) - { - // TestAdaptersPaths could contain environment variables - var testAdapterFullPath = Path.GetFullPath(Environment.ExpandEnvironmentVariables(testadapterPath)); + // Get test adapter paths from RunSettings. + var testAdapterPathsInRunSettings = this.runSettingsManager.QueryRunSettingsNode("RunConfiguration.TestAdaptersPaths"); - if (!this.fileHelper.DirectoryExists(testAdapterFullPath)) - { - invalidAdapterPathArgument = testadapterPath; - throw new DirectoryNotFoundException(CommandLineResources.TestAdapterPathDoesNotExist); - } - - testAdapterFullPaths.Add(testAdapterFullPath); - } - - customAdaptersPath = string.Join(";", testAdapterFullPaths.Distinct().ToArray()); - - this.runSettingsManager.UpdateRunSettingsNode("RunConfiguration.TestAdaptersPaths", customAdaptersPath); - } - catch (Exception e) + if (!string.IsNullOrWhiteSpace(testAdapterPathsInRunSettings)) { - throw new CommandLineException( - string.Format(CultureInfo.CurrentCulture, CommandLineResources.InvalidTestAdapterPathCommand, invalidAdapterPathArgument, e.Message)); + testAdapterPaths.AddRange(SplitPaths(testAdapterPathsInRunSettings)); } + testAdapterPaths.AddRange(SplitPaths(argument)); + customAdaptersPath = testAdapterPaths.Distinct().ToArray(); + + this.runSettingsManager.UpdateRunSettingsNode("RunConfiguration.TestAdaptersPaths", string.Join(";", customAdaptersPath)); this.commandLineOptions.TestAdapterPath = customAdaptersPath; } @@ -216,7 +189,7 @@ public void Initialize(string argument) /// /// Source paths joined by semicolons. /// Paths. - private string[] SplitPaths(string paths) + public static string[] SplitPaths(string paths) { if (string.IsNullOrWhiteSpace(paths)) { diff --git a/src/vstest.console/Processors/Utilities/ArgumentProcessorFactory.cs b/src/vstest.console/Processors/Utilities/ArgumentProcessorFactory.cs index 33b9729c6e..0a87380b91 100644 --- a/src/vstest.console/Processors/Utilities/ArgumentProcessorFactory.cs +++ b/src/vstest.console/Processors/Utilities/ArgumentProcessorFactory.cs @@ -202,11 +202,10 @@ public IArgumentProcessor CreateDefaultActionArgumentProcessor() /// Gets the argument processors that are tagged as special and to be always executed. /// The Lazy's that are returned will initialize the underlying argument processor when first accessed. /// - /// The argument processors that are tagged as special and to be always executed. + /// The argument processors that are tagged as to be always executed. public IEnumerable GetArgumentProcessorsToAlwaysExecute() { - return SpecialCommandToProcessorMap.Values - .Where(lazyProcessor => lazyProcessor.Metadata.Value.IsSpecialCommand && lazyProcessor.Metadata.Value.AlwaysExecute); + return argumentProcessors.Where(lazyProcessor => lazyProcessor.Metadata.Value.AlwaysExecute); } #endregion @@ -220,6 +219,7 @@ public IEnumerable GetArgumentProcessorsToAlwaysExecute() new RunTestsArgumentProcessor(), new RunSpecificTestsArgumentProcessor(), new TestAdapterPathArgumentProcessor(), + new TestAdapterLoadingStrategyArgumentProcessor(), new TestCaseFilterArgumentProcessor(), new ParentProcessIdArgumentProcessor(), new PortArgumentProcessor(), @@ -287,7 +287,7 @@ private void BuildCommandMaps() /// The lazy processor. /// The argument with which the real processor should be initialized. /// The decorated lazy processor. - private static IArgumentProcessor WrapLazyProcessorToInitializeOnInstantiation( + public static IArgumentProcessor WrapLazyProcessorToInitializeOnInstantiation( IArgumentProcessor processor, string initArg = null) { diff --git a/src/vstest.console/Processors/Utilities/ArgumentProcessorPriority.cs b/src/vstest.console/Processors/Utilities/ArgumentProcessorPriority.cs index eb14b21b87..3a3616304e 100644 --- a/src/vstest.console/Processors/Utilities/ArgumentProcessorPriority.cs +++ b/src/vstest.console/Processors/Utilities/ArgumentProcessorPriority.cs @@ -43,10 +43,18 @@ internal enum ArgumentProcessorPriority /// /// Priority of TestAdapterPathArgumentProcessor. + /// /// The priority of TestAdapterPath processor is more than the logger because logger initialization /// loads the extensions which are incomplete if custom test adapter is enabled /// - TestAdapterPath = 10, + TestAdapterPath = 9, + + /// + /// Priority of TestAdapterLoadingStrategyArgumentProcessor. + /// + /// This needs to be higher than most of other arguments, because it affects where we look for test adapters. + /// + TestAdapterLoadingStrategy = 10, /// /// Priority of processors that needs to update runsettings. diff --git a/src/vstest.console/Processors/Utilities/HelpContentPriority.cs b/src/vstest.console/Processors/Utilities/HelpContentPriority.cs index ecd57d18de..27917088a4 100644 --- a/src/vstest.console/Processors/Utilities/HelpContentPriority.cs +++ b/src/vstest.console/Processors/Utilities/HelpContentPriority.cs @@ -22,6 +22,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CommandLine.Processors /// --ListTests /// --Parallel /// --TestAdapterPath + /// --TestAdapterLoadingStrategy /// /// Diagnose/Report /// --Diag @@ -33,7 +34,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CommandLine.Processors /// --Port /// /// Help - /// -Help + /// -�Help /// internal enum HelpContentPriority { @@ -97,6 +98,11 @@ internal enum HelpContentPriority /// TestAdapterPathArgumentProcessorHelpPriority, + /// + /// TestAdapterLoadingStrategyArgumentProcessor Help + /// + TestAdapterLoadingStrategyArgumentProcessorHelpPriority, + /// /// EnableDiagArgumentProcessor Help /// diff --git a/src/vstest.console/Resources/Resources.Designer.cs b/src/vstest.console/Resources/Resources.Designer.cs index eda555c483..46a8a88ca5 100644 --- a/src/vstest.console/Resources/Resources.Designer.cs +++ b/src/vstest.console/Resources/Resources.Designer.cs @@ -1507,6 +1507,39 @@ internal static string SwitchToNoIsolation { } } + /// + /// Looks up a localized string similar to --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + /// This affects adapter loading behavior. + /// + /// Currently supported behaviours: + /// - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + /// If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded, unless Recursive option is also specified. + /// [rest of string was truncated]";. + /// + internal static string TestAdapterLoadingStrategyHelp { + get { + return ResourceManager.GetString("TestAdapterLoadingStrategyHelp", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Specified value ({0}) for /TestAdapterLoadingStrategy is invalid!. + /// + internal static string TestAdapterLoadingStrategyValueInvalid { + get { + return ResourceManager.GetString("TestAdapterLoadingStrategyValueInvalid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to "Recursive" adapter loading strategy is cannot be used by itself. Please specify at least one of: {0}. + /// + internal static string TestAdapterLoadingStrategyValueInvalidRecursive { + get { + return ResourceManager.GetString("TestAdapterLoadingStrategyValueInvalidRecursive", resourceCulture); + } + } + /// /// Looks up a localized string similar to The custom test adapter search path provided was not found, provide a valid path and try again.. /// @@ -1537,6 +1570,15 @@ internal static string TestAdapterPathValueRequired { } } + /// + /// Looks up a localized string similar to The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified!. + /// + internal static string TestAdapterPathValueRequiredWhenStrategyXIsUsed { + get { + return ResourceManager.GetString("TestAdapterPathValueRequiredWhenStrategyXIsUsed", resourceCulture); + } + } + /// /// Looks up a localized string similar to --TestCaseFilter|/TestCaseFilter:<Expression> /// Run tests that match the given expression. diff --git a/src/vstest.console/Resources/Resources.resx b/src/vstest.console/Resources/Resources.resx index d80d990139..654a14e7d3 100644 --- a/src/vstest.console/Resources/Resources.resx +++ b/src/vstest.console/Resources/Resources.resx @@ -560,6 +560,44 @@ The /TestAdapterPath parameter requires a value, which is path of a location containing custom test adapters. Example: /TestAdapterPath:c:\MyCustomAdapters + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded, unless Recursive option is also specified. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + - DefaultRuntimeProviders: Load default runtime providers shipped with Test Platform. + If this is not specified when "Explicit" option is set, a test host provider need to be specified explicitly. + + - ExtensionsDirectory: Load adapters inside Extensions folder. + + - NextToSource: Load adapters next to source. + + - Recursive: Recursively search folders when loading adapters. This requires "Explicit" or "NextToSource" to be specified too. + + Do not translate "Default", "DefaultRuntimeProviders", "ExtensionsDirectory", "NextToSource" or "Recursive". + + + Specified value ({0}) for /TestAdapterLoadingStrategy is invalid! + + + Recursive adapter loading strategy is cannot be used by itself. Please combine with one or more of: {0} + + - Do not translate "Recursive", + - {0} is the strategy names, seperated by comma: for example "Explicit, NextToSource" + + + + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + {0} is the strategy name, "Explicit" for example. + --TestCaseFilter|/TestCaseFilter:<Expression> Run tests that match the given expression. diff --git a/src/vstest.console/Resources/xlf/Resources.cs.xlf b/src/vstest.console/Resources/xlf/Resources.cs.xlf index 064a9ba62c..02b004475f 100644 --- a/src/vstest.console/Resources/xlf/Resources.cs.xlf +++ b/src/vstest.console/Resources/xlf/Resources.cs.xlf @@ -1108,6 +1108,60 @@ Testovací běh se přerušil s chybou {0}. + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded, unless Recursive option is also specified. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + - DefaultRuntimeProviders: Load default runtime providers shipped with Test Platform. + If this is not specified when "Explicit" option is set, a test host provider need to be specified explicitly. + + - ExtensionsDirectory: Load adapters inside Extensions folder. + + - NextToSource: Load adapters next to source. + + - Recursive: Recursively search folders when loading adapters. This requires "Explicit" or "NextToSource" to be specified too. + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + Do not translate "Default", "DefaultRuntimeProviders", "ExtensionsDirectory", "NextToSource" or "Recursive". + + + Specified value ({0}) for /TestAdapterLoadingStrategy is invalid! + Specified value for /TestAdapterLoadingStrategy is invalid! + + + + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + {0} is the strategy name, "Explicit" for example. + + + Recursive adapter loading strategy is cannot be used by itself. Please combine with one or more of: {0} + "Recursive" adapter loading strategy is cannot be used by itself. Please specify at least one of: {0} + + - Do not translate "Recursive", + - {0} is the strategy names, seperated by comma: for example "Explicit, NextToSource" + + \ No newline at end of file diff --git a/src/vstest.console/Resources/xlf/Resources.de.xlf b/src/vstest.console/Resources/xlf/Resources.de.xlf index 43a89b1e2d..0629b33ea0 100644 --- a/src/vstest.console/Resources/xlf/Resources.de.xlf +++ b/src/vstest.console/Resources/xlf/Resources.de.xlf @@ -1108,6 +1108,60 @@ Der Testlauf wurde mit dem Fehler {0} abgebrochen. + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded, unless Recursive option is also specified. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + - DefaultRuntimeProviders: Load default runtime providers shipped with Test Platform. + If this is not specified when "Explicit" option is set, a test host provider need to be specified explicitly. + + - ExtensionsDirectory: Load adapters inside Extensions folder. + + - NextToSource: Load adapters next to source. + + - Recursive: Recursively search folders when loading adapters. This requires "Explicit" or "NextToSource" to be specified too. + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + Do not translate "Default", "DefaultRuntimeProviders", "ExtensionsDirectory", "NextToSource" or "Recursive". + + + Specified value ({0}) for /TestAdapterLoadingStrategy is invalid! + Specified value for /TestAdapterLoadingStrategy is invalid! + + + + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + {0} is the strategy name, "Explicit" for example. + + + Recursive adapter loading strategy is cannot be used by itself. Please combine with one or more of: {0} + "Recursive" adapter loading strategy is cannot be used by itself. Please specify at least one of: {0} + + - Do not translate "Recursive", + - {0} is the strategy names, seperated by comma: for example "Explicit, NextToSource" + + \ No newline at end of file diff --git a/src/vstest.console/Resources/xlf/Resources.es.xlf b/src/vstest.console/Resources/xlf/Resources.es.xlf index 4c7e974124..3871424215 100644 --- a/src/vstest.console/Resources/xlf/Resources.es.xlf +++ b/src/vstest.console/Resources/xlf/Resources.es.xlf @@ -1111,6 +1111,60 @@ La serie de pruebas se ha anulado con el error {0}. + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded, unless Recursive option is also specified. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + - DefaultRuntimeProviders: Load default runtime providers shipped with Test Platform. + If this is not specified when "Explicit" option is set, a test host provider need to be specified explicitly. + + - ExtensionsDirectory: Load adapters inside Extensions folder. + + - NextToSource: Load adapters next to source. + + - Recursive: Recursively search folders when loading adapters. This requires "Explicit" or "NextToSource" to be specified too. + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + Do not translate "Default", "DefaultRuntimeProviders", "ExtensionsDirectory", "NextToSource" or "Recursive". + + + Specified value ({0}) for /TestAdapterLoadingStrategy is invalid! + Specified value for /TestAdapterLoadingStrategy is invalid! + + + + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + {0} is the strategy name, "Explicit" for example. + + + Recursive adapter loading strategy is cannot be used by itself. Please combine with one or more of: {0} + "Recursive" adapter loading strategy is cannot be used by itself. Please specify at least one of: {0} + + - Do not translate "Recursive", + - {0} is the strategy names, seperated by comma: for example "Explicit, NextToSource" + + \ No newline at end of file diff --git a/src/vstest.console/Resources/xlf/Resources.fr.xlf b/src/vstest.console/Resources/xlf/Resources.fr.xlf index a65a8316ff..bf7a15fd6a 100644 --- a/src/vstest.console/Resources/xlf/Resources.fr.xlf +++ b/src/vstest.console/Resources/xlf/Resources.fr.xlf @@ -1108,6 +1108,60 @@ Désolé... Nous n’avons pas pu procéder à la série de tests, car nous avons rencontré l’erreur suivante : {0}. + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded, unless Recursive option is also specified. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + - DefaultRuntimeProviders: Load default runtime providers shipped with Test Platform. + If this is not specified when "Explicit" option is set, a test host provider need to be specified explicitly. + + - ExtensionsDirectory: Load adapters inside Extensions folder. + + - NextToSource: Load adapters next to source. + + - Recursive: Recursively search folders when loading adapters. This requires "Explicit" or "NextToSource" to be specified too. + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + Do not translate "Default", "DefaultRuntimeProviders", "ExtensionsDirectory", "NextToSource" or "Recursive". + + + Specified value ({0}) for /TestAdapterLoadingStrategy is invalid! + Specified value for /TestAdapterLoadingStrategy is invalid! + + + + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + {0} is the strategy name, "Explicit" for example. + + + Recursive adapter loading strategy is cannot be used by itself. Please combine with one or more of: {0} + "Recursive" adapter loading strategy is cannot be used by itself. Please specify at least one of: {0} + + - Do not translate "Recursive", + - {0} is the strategy names, seperated by comma: for example "Explicit, NextToSource" + + \ No newline at end of file diff --git a/src/vstest.console/Resources/xlf/Resources.it.xlf b/src/vstest.console/Resources/xlf/Resources.it.xlf index 8a179cbcf7..aa47c48744 100644 --- a/src/vstest.console/Resources/xlf/Resources.it.xlf +++ b/src/vstest.console/Resources/xlf/Resources.it.xlf @@ -1108,6 +1108,60 @@ Esecuzione dei test interrotta con errore {0}. + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded, unless Recursive option is also specified. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + - DefaultRuntimeProviders: Load default runtime providers shipped with Test Platform. + If this is not specified when "Explicit" option is set, a test host provider need to be specified explicitly. + + - ExtensionsDirectory: Load adapters inside Extensions folder. + + - NextToSource: Load adapters next to source. + + - Recursive: Recursively search folders when loading adapters. This requires "Explicit" or "NextToSource" to be specified too. + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + Do not translate "Default", "DefaultRuntimeProviders", "ExtensionsDirectory", "NextToSource" or "Recursive". + + + Specified value ({0}) for /TestAdapterLoadingStrategy is invalid! + Specified value for /TestAdapterLoadingStrategy is invalid! + + + + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + {0} is the strategy name, "Explicit" for example. + + + Recursive adapter loading strategy is cannot be used by itself. Please combine with one or more of: {0} + "Recursive" adapter loading strategy is cannot be used by itself. Please specify at least one of: {0} + + - Do not translate "Recursive", + - {0} is the strategy names, seperated by comma: for example "Explicit, NextToSource" + + \ No newline at end of file diff --git a/src/vstest.console/Resources/xlf/Resources.ja.xlf b/src/vstest.console/Resources/xlf/Resources.ja.xlf index 43c67530ab..d9bc124831 100644 --- a/src/vstest.console/Resources/xlf/Resources.ja.xlf +++ b/src/vstest.console/Resources/xlf/Resources.ja.xlf @@ -1108,6 +1108,60 @@ テストの実行がエラー {0} により中止されました。 + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded, unless Recursive option is also specified. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + - DefaultRuntimeProviders: Load default runtime providers shipped with Test Platform. + If this is not specified when "Explicit" option is set, a test host provider need to be specified explicitly. + + - ExtensionsDirectory: Load adapters inside Extensions folder. + + - NextToSource: Load adapters next to source. + + - Recursive: Recursively search folders when loading adapters. This requires "Explicit" or "NextToSource" to be specified too. + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + Do not translate "Default", "DefaultRuntimeProviders", "ExtensionsDirectory", "NextToSource" or "Recursive". + + + Specified value ({0}) for /TestAdapterLoadingStrategy is invalid! + Specified value for /TestAdapterLoadingStrategy is invalid! + + + + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + {0} is the strategy name, "Explicit" for example. + + + Recursive adapter loading strategy is cannot be used by itself. Please combine with one or more of: {0} + "Recursive" adapter loading strategy is cannot be used by itself. Please specify at least one of: {0} + + - Do not translate "Recursive", + - {0} is the strategy names, seperated by comma: for example "Explicit, NextToSource" + + \ No newline at end of file diff --git a/src/vstest.console/Resources/xlf/Resources.ko.xlf b/src/vstest.console/Resources/xlf/Resources.ko.xlf index 86be769735..cab7f7b183 100644 --- a/src/vstest.console/Resources/xlf/Resources.ko.xlf +++ b/src/vstest.console/Resources/xlf/Resources.ko.xlf @@ -1108,6 +1108,60 @@ 테스트 실행이 {0} 오류로 인해 중단되었습니다. + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded, unless Recursive option is also specified. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + - DefaultRuntimeProviders: Load default runtime providers shipped with Test Platform. + If this is not specified when "Explicit" option is set, a test host provider need to be specified explicitly. + + - ExtensionsDirectory: Load adapters inside Extensions folder. + + - NextToSource: Load adapters next to source. + + - Recursive: Recursively search folders when loading adapters. This requires "Explicit" or "NextToSource" to be specified too. + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + Do not translate "Default", "DefaultRuntimeProviders", "ExtensionsDirectory", "NextToSource" or "Recursive". + + + Specified value ({0}) for /TestAdapterLoadingStrategy is invalid! + Specified value for /TestAdapterLoadingStrategy is invalid! + + + + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + {0} is the strategy name, "Explicit" for example. + + + Recursive adapter loading strategy is cannot be used by itself. Please combine with one or more of: {0} + "Recursive" adapter loading strategy is cannot be used by itself. Please specify at least one of: {0} + + - Do not translate "Recursive", + - {0} is the strategy names, seperated by comma: for example "Explicit, NextToSource" + + \ No newline at end of file diff --git a/src/vstest.console/Resources/xlf/Resources.pl.xlf b/src/vstest.console/Resources/xlf/Resources.pl.xlf index 4eea286a34..4f89c240ee 100644 --- a/src/vstest.console/Resources/xlf/Resources.pl.xlf +++ b/src/vstest.console/Resources/xlf/Resources.pl.xlf @@ -1108,6 +1108,60 @@ Przebieg testowy został przerwany z powodu błędu {0}. + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded, unless Recursive option is also specified. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + - DefaultRuntimeProviders: Load default runtime providers shipped with Test Platform. + If this is not specified when "Explicit" option is set, a test host provider need to be specified explicitly. + + - ExtensionsDirectory: Load adapters inside Extensions folder. + + - NextToSource: Load adapters next to source. + + - Recursive: Recursively search folders when loading adapters. This requires "Explicit" or "NextToSource" to be specified too. + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + Do not translate "Default", "DefaultRuntimeProviders", "ExtensionsDirectory", "NextToSource" or "Recursive". + + + Specified value ({0}) for /TestAdapterLoadingStrategy is invalid! + Specified value for /TestAdapterLoadingStrategy is invalid! + + + + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + {0} is the strategy name, "Explicit" for example. + + + Recursive adapter loading strategy is cannot be used by itself. Please combine with one or more of: {0} + "Recursive" adapter loading strategy is cannot be used by itself. Please specify at least one of: {0} + + - Do not translate "Recursive", + - {0} is the strategy names, seperated by comma: for example "Explicit, NextToSource" + + \ No newline at end of file diff --git a/src/vstest.console/Resources/xlf/Resources.pt-BR.xlf b/src/vstest.console/Resources/xlf/Resources.pt-BR.xlf index ccc01cb4dd..8214510b29 100644 --- a/src/vstest.console/Resources/xlf/Resources.pt-BR.xlf +++ b/src/vstest.console/Resources/xlf/Resources.pt-BR.xlf @@ -1108,6 +1108,60 @@ Altere o prefixo de nível de diagnóstico do agente de console, como mostrado a Execução de Teste Abortada com Erro {0}. + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded, unless Recursive option is also specified. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + - DefaultRuntimeProviders: Load default runtime providers shipped with Test Platform. + If this is not specified when "Explicit" option is set, a test host provider need to be specified explicitly. + + - ExtensionsDirectory: Load adapters inside Extensions folder. + + - NextToSource: Load adapters next to source. + + - Recursive: Recursively search folders when loading adapters. This requires "Explicit" or "NextToSource" to be specified too. + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + Do not translate "Default", "DefaultRuntimeProviders", "ExtensionsDirectory", "NextToSource" or "Recursive". + + + Specified value ({0}) for /TestAdapterLoadingStrategy is invalid! + Specified value for /TestAdapterLoadingStrategy is invalid! + + + + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + {0} is the strategy name, "Explicit" for example. + + + Recursive adapter loading strategy is cannot be used by itself. Please combine with one or more of: {0} + "Recursive" adapter loading strategy is cannot be used by itself. Please specify at least one of: {0} + + - Do not translate "Recursive", + - {0} is the strategy names, seperated by comma: for example "Explicit, NextToSource" + + \ No newline at end of file diff --git a/src/vstest.console/Resources/xlf/Resources.ru.xlf b/src/vstest.console/Resources/xlf/Resources.ru.xlf index 0fd2965937..eae4cd1db2 100644 --- a/src/vstest.console/Resources/xlf/Resources.ru.xlf +++ b/src/vstest.console/Resources/xlf/Resources.ru.xlf @@ -1108,6 +1108,60 @@ Тестовый запуск прерван с ошибкой {0}. + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded, unless Recursive option is also specified. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + - DefaultRuntimeProviders: Load default runtime providers shipped with Test Platform. + If this is not specified when "Explicit" option is set, a test host provider need to be specified explicitly. + + - ExtensionsDirectory: Load adapters inside Extensions folder. + + - NextToSource: Load adapters next to source. + + - Recursive: Recursively search folders when loading adapters. This requires "Explicit" or "NextToSource" to be specified too. + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + Do not translate "Default", "DefaultRuntimeProviders", "ExtensionsDirectory", "NextToSource" or "Recursive". + + + Specified value ({0}) for /TestAdapterLoadingStrategy is invalid! + Specified value for /TestAdapterLoadingStrategy is invalid! + + + + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + {0} is the strategy name, "Explicit" for example. + + + Recursive adapter loading strategy is cannot be used by itself. Please combine with one or more of: {0} + "Recursive" adapter loading strategy is cannot be used by itself. Please specify at least one of: {0} + + - Do not translate "Recursive", + - {0} is the strategy names, seperated by comma: for example "Explicit, NextToSource" + + \ No newline at end of file diff --git a/src/vstest.console/Resources/xlf/Resources.tr.xlf b/src/vstest.console/Resources/xlf/Resources.tr.xlf index ecc7dfdba6..9f14fce1c7 100644 --- a/src/vstest.console/Resources/xlf/Resources.tr.xlf +++ b/src/vstest.console/Resources/xlf/Resources.tr.xlf @@ -1108,6 +1108,60 @@ Günlükler için izleme düzeyini aşağıda gösterildiği gibi değiştirin Test Çalıştırması {0} hatasıyla durduruldu. + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded, unless Recursive option is also specified. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + - DefaultRuntimeProviders: Load default runtime providers shipped with Test Platform. + If this is not specified when "Explicit" option is set, a test host provider need to be specified explicitly. + + - ExtensionsDirectory: Load adapters inside Extensions folder. + + - NextToSource: Load adapters next to source. + + - Recursive: Recursively search folders when loading adapters. This requires "Explicit" or "NextToSource" to be specified too. + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + Do not translate "Default", "DefaultRuntimeProviders", "ExtensionsDirectory", "NextToSource" or "Recursive". + + + Specified value ({0}) for /TestAdapterLoadingStrategy is invalid! + Specified value for /TestAdapterLoadingStrategy is invalid! + + + + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + {0} is the strategy name, "Explicit" for example. + + + Recursive adapter loading strategy is cannot be used by itself. Please combine with one or more of: {0} + "Recursive" adapter loading strategy is cannot be used by itself. Please specify at least one of: {0} + + - Do not translate "Recursive", + - {0} is the strategy names, seperated by comma: for example "Explicit, NextToSource" + + \ No newline at end of file diff --git a/src/vstest.console/Resources/xlf/Resources.xlf b/src/vstest.console/Resources/xlf/Resources.xlf index c289ffcb47..f59c32e300 100644 --- a/src/vstest.console/Resources/xlf/Resources.xlf +++ b/src/vstest.console/Resources/xlf/Resources.xlf @@ -901,6 +901,60 @@ Format : TestRunParameters.Parameter(name="<name>", value="<value>") Test Run Aborted with error {0}. + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded, unless Recursive option is also specified. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + - DefaultRuntimeProviders: Load default runtime providers shipped with Test Platform. + If this is not specified when "Explicit" option is set, a test host provider need to be specified explicitly. + + - ExtensionsDirectory: Load adapters inside Extensions folder. + + - NextToSource: Load adapters next to source. + + - Recursive: Recursively search folders when loading adapters. This requires "Explicit" or "NextToSource" to be specified too. + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + Do not translate "Default", "DefaultRuntimeProviders", "ExtensionsDirectory", "NextToSource" or "Recursive". + + + Specified value ({0}) for /TestAdapterLoadingStrategy is invalid! + Specified value for /TestAdapterLoadingStrategy is invalid! + + + + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + {0} is the strategy name, "Explicit" for example. + + + Recursive adapter loading strategy is cannot be used by itself. Please combine with one or more of: {0} + "Recursive" adapter loading strategy is cannot be used by itself. Please specify at least one of: {0} + + - Do not translate "Recursive", + - {0} is the strategy names, seperated by comma: for example "Explicit, NextToSource" + + \ No newline at end of file diff --git a/src/vstest.console/Resources/xlf/Resources.zh-Hans.xlf b/src/vstest.console/Resources/xlf/Resources.zh-Hans.xlf index d4c3310596..8a473e6d3e 100644 --- a/src/vstest.console/Resources/xlf/Resources.zh-Hans.xlf +++ b/src/vstest.console/Resources/xlf/Resources.zh-Hans.xlf @@ -1108,6 +1108,60 @@ 测试运行已中止,出现错误 {0}。 + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded, unless Recursive option is also specified. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + - DefaultRuntimeProviders: Load default runtime providers shipped with Test Platform. + If this is not specified when "Explicit" option is set, a test host provider need to be specified explicitly. + + - ExtensionsDirectory: Load adapters inside Extensions folder. + + - NextToSource: Load adapters next to source. + + - Recursive: Recursively search folders when loading adapters. This requires "Explicit" or "NextToSource" to be specified too. + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + Do not translate "Default", "DefaultRuntimeProviders", "ExtensionsDirectory", "NextToSource" or "Recursive". + + + Specified value ({0}) for /TestAdapterLoadingStrategy is invalid! + Specified value for /TestAdapterLoadingStrategy is invalid! + + + + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + {0} is the strategy name, "Explicit" for example. + + + Recursive adapter loading strategy is cannot be used by itself. Please combine with one or more of: {0} + "Recursive" adapter loading strategy is cannot be used by itself. Please specify at least one of: {0} + + - Do not translate "Recursive", + - {0} is the strategy names, seperated by comma: for example "Explicit, NextToSource" + + \ No newline at end of file diff --git a/src/vstest.console/Resources/xlf/Resources.zh-Hant.xlf b/src/vstest.console/Resources/xlf/Resources.zh-Hant.xlf index f818e20189..a4525b724a 100644 --- a/src/vstest.console/Resources/xlf/Resources.zh-Hant.xlf +++ b/src/vstest.console/Resources/xlf/Resources.zh-Hant.xlf @@ -1108,6 +1108,60 @@ 測試執行已中止,錯誤 {0}。 + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded, unless Recursive option is also specified. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + - DefaultRuntimeProviders: Load default runtime providers shipped with Test Platform. + If this is not specified when "Explicit" option is set, a test host provider need to be specified explicitly. + + - ExtensionsDirectory: Load adapters inside Extensions folder. + + - NextToSource: Load adapters next to source. + + - Recursive: Recursively search folders when loading adapters. This requires "Explicit" or "NextToSource" to be specified too. + + --TestAdapterLoadingStrategy|/TestAdapterLoadingStrategy:<strategy> + This affects adapter loading behavior. + + Currently supported behaviours: + - Explicit: Test Plarform will only load adapters specified by /TestAdapterPath (or RunConfiguration.TestAdaptersPaths node). + If a specific adapter path is provided, adapter will be loaded; if a directory path is provided adapters directly in that folder will be loaded. + If no adapter path is specified, test run will fail. + This will imply /InIsolation switch and force the tests to be run in an isolated process. + + - Default: Test Platfrom will load adapters is if this argument has not beed specified. + It will pick up extensions from next to source, provided aditional adapter paths and from the default directory. + + Do not translate "Default", "DefaultRuntimeProviders", "ExtensionsDirectory", "NextToSource" or "Recursive". + + + Specified value ({0}) for /TestAdapterLoadingStrategy is invalid! + Specified value for /TestAdapterLoadingStrategy is invalid! + + + + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + The /TestAdapterPath parameter needs to be provided when "{0}" test adapter loading strategy is specified! + {0} is the strategy name, "Explicit" for example. + + + Recursive adapter loading strategy is cannot be used by itself. Please combine with one or more of: {0} + "Recursive" adapter loading strategy is cannot be used by itself. Please specify at least one of: {0} + + - Do not translate "Recursive", + - {0} is the strategy names, seperated by comma: for example "Explicit, NextToSource" + + \ No newline at end of file diff --git a/test/vstest.console.UnitTests/Processors/RunSpecificTestsArgumentProcessorTests.cs b/test/vstest.console.UnitTests/Processors/RunSpecificTestsArgumentProcessorTests.cs index 3a79cd4301..b0c5717421 100644 --- a/test/vstest.console.UnitTests/Processors/RunSpecificTestsArgumentProcessorTests.cs +++ b/test/vstest.console.UnitTests/Processors/RunSpecificTestsArgumentProcessorTests.cs @@ -345,7 +345,7 @@ public void ExecutorExecuteShouldForValidSourcesAndNoTestsDiscoveredShouldLogWar this.ResetAndAddSourceToCommandLineOptions(); // Setting some test adapter path - CommandLineOptions.Instance.TestAdapterPath = @"C:\Foo"; + CommandLineOptions.Instance.TestAdapterPath = new[] { @"C:\Foo" }; mockDiscoveryRequest.Setup(dr => dr.DiscoverAsync()).Raises(dr => dr.OnDiscoveredTests += null, new DiscoveredTestsEventArgs(new List())); mockTestPlatform.Setup(tp => tp.CreateDiscoveryRequest(It.IsAny(), It.IsAny(), It.IsAny())).Returns(mockDiscoveryRequest.Object); diff --git a/test/vstest.console.UnitTests/Processors/TestAdapterLoadingStrategyArgumentProcessorTests.cs b/test/vstest.console.UnitTests/Processors/TestAdapterLoadingStrategyArgumentProcessorTests.cs new file mode 100644 index 0000000000..e5371d60e6 --- /dev/null +++ b/test/vstest.console.UnitTests/Processors/TestAdapterLoadingStrategyArgumentProcessorTests.cs @@ -0,0 +1,133 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestPlatform.CommandLine.UnitTests.Processors +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Reflection; + + using Microsoft.VisualStudio.TestPlatform.CommandLine.Processors; + using Microsoft.VisualStudio.TestPlatform.Common; + using Microsoft.VisualStudio.TestPlatform.Common.Interfaces; + using Microsoft.VisualStudio.TestPlatform.Common.Utilities; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; + using Microsoft.VisualStudio.TestPlatform.Utilities; + using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers; + using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + using Moq; + + [TestClass] + public class TestAdapterLoadingStrategyArgumentProcessorTests + { + RunSettings currentActiveSetting; + + [TestInitialize] + public void TestInit() + { + currentActiveSetting = RunSettingsManager.Instance.ActiveRunSettings; + } + + [TestCleanup] + public void TestClean() + { + RunSettingsManager.Instance.SetActiveRunSettings(currentActiveSetting); + } + + [TestMethod] + [TestCategory("Windows")] + public void InitializeShouldHonorEnvironmentVariablesInTestAdapterPaths() + { + var runSettingsXml = "%temp%\\adapters1;%temp%\\adapters2"; + var runSettings = new RunSettings(); + runSettings.LoadSettingsXml(runSettingsXml); + RunSettingsManager.Instance.SetActiveRunSettings(runSettings); + var mockFileHelper = new Mock(); + var mockOutput = new Mock(); + + mockFileHelper.Setup(x => x.DirectoryExists(It.IsAny())).Returns(true); + mockFileHelper.Setup(x => x.GetFullPath(It.IsAny())).Returns((Func)(s => Path.GetFullPath(s))); + + var executor = new TestAdapterLoadingStrategyArgumentExecutor(CommandLineOptions.Instance, RunSettingsManager.Instance, mockOutput.Object, mockFileHelper.Object); + + executor.Initialize(TestAdapterLoadingStrategyArgumentExecutor.DefaultStrategy); + var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(RunSettingsManager.Instance.ActiveRunSettings.SettingsXml); + + var tempPath = Path.GetFullPath(Environment.ExpandEnvironmentVariables("%temp%")); + Assert.AreEqual(string.Format("{0}\\adapters1;{0}\\adapters2", tempPath), runConfiguration.TestAdaptersPaths); + } + + [TestMethod] + [TestCategory("Windows")] + public void InitializeShouldAddRightAdapterPathInErrorMessage() + { + var runSettingsXml = "d:\\users"; + var runSettings = new RunSettings(); + runSettings.LoadSettingsXml(runSettingsXml); + RunSettingsManager.Instance.SetActiveRunSettings(runSettings); + var mockFileHelper = new Mock(); + var mockOutput = new Mock(); + + mockFileHelper.Setup(x => x.DirectoryExists("d:\\users")).Returns(false); + mockFileHelper.Setup(x => x.DirectoryExists("c:\\users")).Returns(true); + var executor = new TestAdapterLoadingStrategyArgumentExecutor(CommandLineOptions.Instance, RunSettingsManager.Instance, mockOutput.Object, mockFileHelper.Object); + + var message = string.Format( + @"The path '{0}' specified in the 'TestAdapterPath' is invalid. Error: {1}", + "d:\\users", + "The custom test adapter search path provided was not found, provide a valid path and try again."); + + var isExceptionThrown = false; + try + { + executor.Initialize(TestAdapterLoadingStrategyArgumentExecutor.DefaultStrategy); + } + catch (Exception ex) + { + isExceptionThrown = true; + Assert.IsTrue(ex is CommandLineException); + Assert.AreEqual(message, ex.Message); + } + + Assert.IsTrue(isExceptionThrown); + } + + + [TestMethod] + public void InitializeShouldThrowIfPathDoesNotExist() + { + var folder = "C:\\temp\\thisfolderdoesnotexist"; + var runSettingsXml = ""+folder+""; + var runSettings = new RunSettings(); + + runSettings.LoadSettingsXml(runSettingsXml); + RunSettingsManager.Instance.SetActiveRunSettings(runSettings); + + var mockOutput = new Mock(); + var executor = new TestAdapterLoadingStrategyArgumentExecutor(CommandLineOptions.Instance, RunSettingsManager.Instance, mockOutput.Object, new FileHelper()); + + var message = string.Format( + @"The path '{0}' specified in the 'TestAdapterPath' is invalid. Error: {1}", + folder, + "The custom test adapter search path provided was not found, provide a valid path and try again."); + + var isExceptionThrown = false; + + try + { + executor.Initialize(TestAdapterLoadingStrategyArgumentExecutor.DefaultStrategy); + } + catch (Exception ex) + { + isExceptionThrown = true; + Assert.IsTrue(ex is CommandLineException); + Assert.AreEqual(message, ex.Message); + } + + Assert.IsTrue(isExceptionThrown); + } + } +} \ No newline at end of file diff --git a/test/vstest.console.UnitTests/Processors/TestAdapterPathArgumentProcessorTests.cs b/test/vstest.console.UnitTests/Processors/TestAdapterPathArgumentProcessorTests.cs index 7069c4a4b4..c950236987 100644 --- a/test/vstest.console.UnitTests/Processors/TestAdapterPathArgumentProcessorTests.cs +++ b/test/vstest.console.UnitTests/Processors/TestAdapterPathArgumentProcessorTests.cs @@ -127,36 +127,6 @@ public void InitializeShouldThrowIfArgumentIsAWhiteSpace() Assert.IsTrue(isExceptionThrown); } - [TestMethod] - public void InitializeShouldThrowIfPathDoesNotExist() - { - var mockRunSettingsProvider = new Mock(); - var mockOutput = new Mock(); - var executor = new TestAdapterPathArgumentExecutor(CommandLineOptions.Instance, mockRunSettingsProvider.Object, mockOutput.Object, new FileHelper()); - - var folder = "C:\\temp\\thisfolderdoesnotexist"; - - var message = string.Format( - @"The path '{0}' specified in the 'TestAdapterPath' is invalid. Error: {1}", - folder, - "The custom test adapter search path provided was not found, provide a valid path and try again."); - - var isExceptionThrown = false; - - try - { - executor.Initialize(folder); - } - catch (Exception ex) - { - isExceptionThrown = true; - Assert.IsTrue(ex is CommandLineException); - Assert.AreEqual(message, ex.Message); - } - - Assert.IsTrue(isExceptionThrown); - } - [TestMethod] public void InitializeShouldUpdateTestAdapterPathInRunSettings() { @@ -230,62 +200,6 @@ public void InitializeShouldMergeMultipleTestAdapterPathsWithPathsInRunSettings( Assert.AreEqual("d:\\users;f:\\users;c:\\users;e:\\users", runConfiguration.TestAdaptersPaths); } - [TestMethod] - [TestCategory("Windows")] - public void InitializeShouldHonorEnvironmentVariablesInTestAdapterPaths() - { - var runSettingsXml = "%temp%\\adapters1"; - var runSettings = new RunSettings(); - runSettings.LoadSettingsXml(runSettingsXml); - RunSettingsManager.Instance.SetActiveRunSettings(runSettings); - var mockFileHelper = new Mock(); - var mockOutput = new Mock(); - - mockFileHelper.Setup(x => x.DirectoryExists(It.IsAny())).Returns(true); - var executor = new TestAdapterPathArgumentExecutor(CommandLineOptions.Instance, RunSettingsManager.Instance, mockOutput.Object, mockFileHelper.Object); - - executor.Initialize("%temp%\\adapters2"); - var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(RunSettingsManager.Instance.ActiveRunSettings.SettingsXml); - - var tempPath = Path.GetFullPath(Environment.ExpandEnvironmentVariables("%temp%")); - Assert.AreEqual(string.Format("{0}\\adapters1;{0}\\adapters2", tempPath), runConfiguration.TestAdaptersPaths); - } - - [TestMethod] - [TestCategory("Windows")] - public void InitializeShouldAddRightAdapterPathInErrorMessage() - { - var runSettingsXml = "d:\\users"; - var runSettings = new RunSettings(); - runSettings.LoadSettingsXml(runSettingsXml); - RunSettingsManager.Instance.SetActiveRunSettings(runSettings); - var mockFileHelper = new Mock(); - var mockOutput = new Mock(); - - mockFileHelper.Setup(x => x.DirectoryExists("d:\\users")).Returns(false); - mockFileHelper.Setup(x => x.DirectoryExists("c:\\users")).Returns(true); - var executor = new TestAdapterPathArgumentExecutor(CommandLineOptions.Instance, RunSettingsManager.Instance, mockOutput.Object, mockFileHelper.Object); - - var message = string.Format( - @"The path '{0}' specified in the 'TestAdapterPath' is invalid. Error: {1}", - "d:\\users", - "The custom test adapter search path provided was not found, provide a valid path and try again."); - - var isExceptionThrown = false; - try - { - executor.Initialize("c:\\users"); - } - catch (Exception ex) - { - isExceptionThrown = true; - Assert.IsTrue(ex is CommandLineException); - Assert.AreEqual(message, ex.Message); - } - - Assert.IsTrue(isExceptionThrown); - } - [TestMethod] [TestCategory("Windows")] public void InitializeShouldTrimTrailingAndLeadingDoubleQuotes()