diff --git a/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginCache.cs b/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginCache.cs index f6c987f37c..a66bb7b6ca 100644 --- a/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginCache.cs +++ b/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginCache.cs @@ -295,6 +295,15 @@ public void ClearExtensions() this.TestExtensions?.InvalidateCache(); } + /// + /// Add search directories to assembly resolver + /// + /// + public void AddResolverSearchDirectories(string[] directories) + { + assemblyResolver.AddSearchDirectories(directories); + } + #endregion #region Utility methods @@ -486,7 +495,7 @@ private Dictionary GetTestExtensions(extensionPaths); } - private void SetupAssemblyResolver(string extensionAssembly) + protected void SetupAssemblyResolver(string extensionAssembly) { IList resolutionPaths; diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManager.cs index c2b3c6796a..800edb78ea 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManager.cs @@ -37,12 +37,6 @@ internal class ProxyExecutionManager : ProxyOperationManager, IProxyExecutionMan private bool skipDefaultAdapters; private readonly IFileHelper fileHelper; - // Only send coverlet inproc datacollector dll to be initialized via testhost, - // ideally this should get initialized via InProcessDC Node in runsettings, but - // somehow it is failing, hence putting this ugly HACK, to fix issues like - // https://developercommunity.visualstudio.com/content/problem/738856/could-not-load-file-or-assembly-microsoftintellitr.html - private const string CoverletDataCollector = "coverlet.collector.dll"; - /// public bool IsInitialized { get; private set; } = false; @@ -54,7 +48,7 @@ internal class ProxyExecutionManager : ProxyOperationManager, IProxyExecutionMan /// The Request Data for providing services and data for Run. /// Test request sender instance. /// Test host manager for this proxy. - public ProxyExecutionManager(IRequestData requestData, ITestRequestSender requestSender, ITestRuntimeProvider testHostManager) : + public ProxyExecutionManager(IRequestData requestData, ITestRequestSender requestSender, ITestRuntimeProvider testHostManager) : this(requestData, requestSender, testHostManager, JsonDataSerializer.Instance, new FileHelper()) { } @@ -108,7 +102,7 @@ public virtual int StartTestRun(TestRunCriteria testRunCriteria, ITestRunEventsH { EqtTrace.Verbose("ProxyExecutionManager: Test host is always Lazy initialize."); } - + var testSources = new List(testRunCriteria.HasSpecificSources ? testRunCriteria.Sources : // If the test execution is with a test filter, group them by sources testRunCriteria.Tests.GroupBy(tc => tc.Source).Select(g => g.Key)); @@ -118,7 +112,7 @@ public virtual int StartTestRun(TestRunCriteria testRunCriteria, ITestRunEventsH if (this.isCommunicationEstablished) { this.CancellationTokenSource.Token.ThrowTestPlatformExceptionIfCancellationRequested(); - + this.InitializeExtensions(testSources); // This code should be in sync with InProcessProxyExecutionManager.StartTestRun executionContext @@ -181,7 +175,7 @@ public virtual int StartTestRun(TestRunCriteria testRunCriteria, ITestRunEventsH public virtual void Cancel(ITestRunEventsHandler eventHandler) { // Just in case ExecuteAsync isn't called yet, set the eventhandler - if(this.baseTestRunEventsHandler == null) + if (this.baseTestRunEventsHandler == null) { this.baseTestRunEventsHandler = eventHandler; } @@ -207,7 +201,7 @@ public virtual int LaunchProcessWithDebuggerAttached(TestProcessStartInfo testPr public void Abort(ITestRunEventsHandler eventHandler) { // Just in case ExecuteAsync isn't called yet, set the eventhandler - if(this.baseTestRunEventsHandler == null) + if (this.baseTestRunEventsHandler == null) { this.baseTestRunEventsHandler = eventHandler; } @@ -238,7 +232,7 @@ public void HandleRawMessage(string rawMessage) { var message = this.dataSerializer.DeserializeMessage(rawMessage); - if(string.Equals(message.MessageType, MessageType.ExecutionComplete)) + if (string.Equals(message.MessageType, MessageType.ExecutionComplete)) { this.Close(); } @@ -267,9 +261,6 @@ private void LogMessage(TestMessageLevel testMessageLevel, string message) private void InitializeExtensions(IEnumerable sources) { var extensions = TestPluginCache.Instance.GetExtensionPaths(TestPlatformConstants.TestAdapterEndsWithPattern, this.skipDefaultAdapters); - - // remove this line once we figure out why coverlet inproc DC is not initialized via runsetting inproc node. - extensions = extensions.Concat(TestPluginCache.Instance.GetExtensionPaths(ProxyExecutionManager.CoverletDataCollector, true)).ToList(); // Filter out non existing extensions var nonExistingExtensions = extensions.Where(extension => !this.fileHelper.Exists(extension)); diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/DataCollection/InProcDataCollector.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/DataCollection/InProcDataCollector.cs index 64f4be014a..140750b6bd 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/DataCollection/InProcDataCollector.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/DataCollection/InProcDataCollector.cs @@ -4,10 +4,11 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection { using System; + using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; - + using Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection.Interfaces; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection; @@ -45,7 +46,7 @@ public InProcDataCollector( string assemblyQualifiedName, TypeInfo interfaceTypeInfo, string configXml) - : this(codeBase, assemblyQualifiedName, interfaceTypeInfo, configXml, new PlatformAssemblyLoadContext()) + : this(codeBase, assemblyQualifiedName, interfaceTypeInfo, configXml, new PlatformAssemblyLoadContext(), TestPluginCache.Instance) { } @@ -62,7 +63,7 @@ public InProcDataCollector( /// /// /// - internal InProcDataCollector(string codeBase, string assemblyQualifiedName, TypeInfo interfaceTypeInfo, string configXml, IAssemblyLoadContext assemblyLoadContext) + internal InProcDataCollector(string codeBase, string assemblyQualifiedName, TypeInfo interfaceTypeInfo, string configXml, IAssemblyLoadContext assemblyLoadContext, TestPluginCache testPluginCache) { this.configXml = configXml; this.assemblyLoadContext = assemblyLoadContext; @@ -75,6 +76,10 @@ internal InProcDataCollector(string codeBase, string assemblyQualifiedName, Type // If we're loading coverlet collector we skip to check the version of assembly // to allow upgrade throught nuget package filterPredicate = (x) => x.FullName.Equals(Constants.CoverletDataCollectorTypeName) && interfaceTypeInfo.IsAssignableFrom(x.GetTypeInfo()); + + // Coverlet collector is consumed as nuget package we need to add assemblies directory to resolver to correctly load references. + Debug.Assert(Path.IsPathRooted(codeBase), "Absolute path expected"); + testPluginCache.AddResolverSearchDirectories(new string[] { Path.GetDirectoryName(codeBase) }); } else { diff --git a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DotnetTestHostManager.cs b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DotnetTestHostManager.cs index 3408ef3a67..8d55c50e5a 100644 --- a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DotnetTestHostManager.cs +++ b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DotnetTestHostManager.cs @@ -45,7 +45,6 @@ public class DotnetTestHostManager : ITestRuntimeProvider private const string DotnetTestHostUri = "HostProvider://DotnetTestHost"; private const string DotnetTestHostFriendlyName = "DotnetTestHost"; private const string TestAdapterRegexPattern = @"TestAdapter.dll"; - private const string CoverletDataCollectorRegexPattern = @"coverlet.collector.dll"; private IDotnetHostHelper dotnetHostHelper; private IEnvironment platformEnvironment; @@ -316,11 +315,6 @@ public IEnumerable GetTestPlatformExtensions(IEnumerable sources extensionPaths.AddRange(this.fileHelper.EnumerateFiles(sourceDirectory, SearchOption.TopDirectoryOnly, TestAdapterRegexPattern)); } - if (extensions != null && extensions.Any()) - { - extensionPaths.AddRange(extensions.Where(x => x.EndsWith(CoverletDataCollectorRegexPattern, StringComparison.OrdinalIgnoreCase))); - } - return extensionPaths; } diff --git a/src/vstest.console/Processors/CollectArgumentProcessor.cs b/src/vstest.console/Processors/CollectArgumentProcessor.cs index cce43f215c..f603e2314c 100644 --- a/src/vstest.console/Processors/CollectArgumentProcessor.cs +++ b/src/vstest.console/Processors/CollectArgumentProcessor.cs @@ -7,12 +7,15 @@ namespace Microsoft.VisualStudio.TestPlatform.CommandLine.Processors using System.Collections.Generic; using System.Globalization; + using System.IO; 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.ObjectModel.Utilities; 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; /// @@ -58,7 +61,7 @@ public Lazy Executor { if (this.executor == null) { - this.executor = new Lazy(() => new CollectArgumentExecutor(RunSettingsManager.Instance)); + this.executor = new Lazy(() => new CollectArgumentExecutor(RunSettingsManager.Instance, new FileHelper())); } return this.executor; @@ -71,7 +74,7 @@ public Lazy Executor } } - + internal class CollectArgumentProcessorCapabilities : BaseArgumentProcessorCapabilities { public override string CommandName => CollectArgumentProcessor.CommandName; @@ -90,11 +93,13 @@ internal class CollectArgumentProcessorCapabilities : BaseArgumentProcessorCapab /// internal class CollectArgumentExecutor : IArgumentExecutor { - private IRunSettingsProvider runSettingsManager; + private readonly IRunSettingsProvider runSettingsManager; + private readonly IFileHelper fileHelper; internal static List EnabledDataCollectors = new List(); - internal CollectArgumentExecutor(IRunSettingsProvider runSettingsManager) + internal CollectArgumentExecutor(IRunSettingsProvider runSettingsManager, IFileHelper fileHelper) { this.runSettingsManager = runSettingsManager; + this.fileHelper = fileHelper; } /// @@ -113,11 +118,29 @@ public void Initialize(string argument) argument)); } - if(InferRunSettingsHelper.IsTestSettingsEnabled(this.runSettingsManager.ActiveRunSettings.SettingsXml)) + if (InferRunSettingsHelper.IsTestSettingsEnabled(this.runSettingsManager.ActiveRunSettings.SettingsXml)) { throw new SettingsException(string.Format(CommandLineResources.CollectWithTestSettingErrorMessage, argument)); } - AddDataCollectorToRunSettings(argument, this.runSettingsManager); + AddDataCollectorToRunSettings(argument, this.runSettingsManager, this.fileHelper); + } + + /// + /// Returns coverlet codebase searching coverlet.collector.dll assembly inside adaptersPaths + /// + private static string GetCoverletCodeBasePath(IRunSettingsProvider runSettingProvider, IFileHelper fileHelper) + { + foreach (string adapterPath in RunSettingsUtilities.GetTestAdaptersPaths(runSettingProvider.ActiveRunSettings.SettingsXml)) + { + string collectorPath = Path.Combine(adapterPath, CoverletConstants.CoverletDataCollectorCodebase); + if (fileHelper.Exists(collectorPath)) + { + EqtTrace.Verbose("CoverletDataCollector in-process codeBase path '{0}'", collectorPath); + return collectorPath; + } + } + + return null; } /// @@ -146,7 +169,7 @@ internal static void EnableDataCollectorUsingFriendlyName(string argument, DataC /// /// Enables coverlet inproc datacollector /// - internal static void EnableCoverletInProcDataCollector(string argument, DataCollectionRunSettings dataCollectionRunSettings) + internal static void EnableCoverletInProcDataCollector(string argument, DataCollectionRunSettings dataCollectionRunSettings, IRunSettingsProvider runSettingProvider, IFileHelper fileHelper) { DataCollectorSettings dataCollectorSettings = null; @@ -156,7 +179,7 @@ internal static void EnableCoverletInProcDataCollector(string argument, DataColl dataCollectorSettings = new DataCollectorSettings(); dataCollectorSettings.FriendlyName = argument; dataCollectorSettings.AssemblyQualifiedName = CoverletConstants.CoverletDataCollectorAssemblyQualifiedName; - dataCollectorSettings.CodeBase = CoverletConstants.CoverletDataCollectorCodebase; + dataCollectorSettings.CodeBase = GetCoverletCodeBasePath(runSettingProvider, fileHelper) ?? CoverletConstants.CoverletDataCollectorCodebase; dataCollectorSettings.IsEnabled = true; dataCollectionRunSettings.DataCollectorSettingsList.Add(dataCollectorSettings); } @@ -186,7 +209,7 @@ private static bool DoesDataCollectorSettingsExist(string friendlyName, return false; } - internal static void AddDataCollectorToRunSettings(string argument, IRunSettingsProvider runSettingsManager) + internal static void AddDataCollectorToRunSettings(string argument, IRunSettingsProvider runSettingsManager, IFileHelper fileHelper) { EnabledDataCollectors.Add(argument.ToLower()); @@ -198,7 +221,7 @@ internal static void AddDataCollectorToRunSettings(string argument, IRunSettings } var dataCollectionRunSettings = XmlRunSettingsUtilities.GetDataCollectionRunSettings(settings) ?? new DataCollectionRunSettings(); - var inProcDataCollectionRunSettings = XmlRunSettingsUtilities.GetInProcDataCollectionRunSettings(settings) + var inProcDataCollectionRunSettings = XmlRunSettingsUtilities.GetInProcDataCollectionRunSettings(settings) ?? new DataCollectionRunSettings( Constants.InProcDataCollectionRunSettingsName, Constants.InProcDataCollectorsSettingName, @@ -212,7 +235,7 @@ internal static void AddDataCollectorToRunSettings(string argument, IRunSettings if (string.Equals(argument, CoverletConstants.CoverletDataCollectorFriendlyName, StringComparison.OrdinalIgnoreCase)) { // Add inproc data collector to runsetings if coverlet code coverage is enabled - EnableCoverletInProcDataCollector(argument, inProcDataCollectionRunSettings); + EnableCoverletInProcDataCollector(argument, inProcDataCollectionRunSettings, runSettingsManager, fileHelper); runSettingsManager.UpdateRunSettingsNodeInnerXml(Constants.InProcDataCollectionRunSettingsName, inProcDataCollectionRunSettings.ToXml().InnerXml); } } diff --git a/src/vstest.console/Processors/EnableBlameArgumentProcessor.cs b/src/vstest.console/Processors/EnableBlameArgumentProcessor.cs index e98557c82c..8adcf14e02 100644 --- a/src/vstest.console/Processors/EnableBlameArgumentProcessor.cs +++ b/src/vstest.console/Processors/EnableBlameArgumentProcessor.cs @@ -18,7 +18,8 @@ namespace Microsoft.VisualStudio.TestPlatform.CommandLine.Processors using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions; using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces; 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; internal class EnableBlameArgumentProcessor : IArgumentProcessor @@ -61,7 +62,7 @@ public Lazy Executor { if (this.executor == null) { - this.executor = new Lazy(() => new EnableBlameArgumentExecutor(RunSettingsManager.Instance, new PlatformEnvironment())); + this.executor = new Lazy(() => new EnableBlameArgumentExecutor(RunSettingsManager.Instance, new PlatformEnvironment(), new FileHelper())); } return this.executor; @@ -111,13 +112,19 @@ internal class EnableBlameArgumentExecutor : IArgumentExecutor /// private IEnvironment environment; + /// + /// For file related operation + /// + private readonly IFileHelper fileHelper; + #region Constructor - internal EnableBlameArgumentExecutor(IRunSettingsProvider runSettingsManager, IEnvironment environment) + internal EnableBlameArgumentExecutor(IRunSettingsProvider runSettingsManager, IEnvironment environment, IFileHelper fileHelper) { this.runSettingsManager = runSettingsManager; this.environment = environment; this.Output = ConsoleOutput.Instance; + this.fileHelper = fileHelper; } #endregion @@ -182,7 +189,7 @@ private void InitializeBlame(bool enableDump, Dictionary collect LoggerUtilities.AddLoggerToRunSettings(BlameFriendlyName, null, this.runSettingsManager); // Add Blame Data Collector - CollectArgumentExecutor.AddDataCollectorToRunSettings(BlameFriendlyName, this.runSettingsManager); + CollectArgumentExecutor.AddDataCollectorToRunSettings(BlameFriendlyName, this.runSettingsManager, this.fileHelper); // Add default run settings if required. diff --git a/src/vstest.console/Processors/EnableCodeCoverageArgumentProcessor.cs b/src/vstest.console/Processors/EnableCodeCoverageArgumentProcessor.cs index b8d01102b6..f0ca15baa0 100644 --- a/src/vstest.console/Processors/EnableCodeCoverageArgumentProcessor.cs +++ b/src/vstest.console/Processors/EnableCodeCoverageArgumentProcessor.cs @@ -13,6 +13,8 @@ namespace Microsoft.VisualStudio.TestPlatform.CommandLine.Processors using Microsoft.VisualStudio.TestPlatform.Common.Utilities; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; + using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers; + using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces; /// /// The argument processor for enabling data collectors. @@ -57,7 +59,7 @@ public Lazy Executor { if (this.executor == null) { - this.executor = new Lazy(() => new EnableCodeCoverageArgumentExecutor(CommandLineOptions.Instance, RunSettingsManager.Instance)); + this.executor = new Lazy(() => new EnableCodeCoverageArgumentExecutor(CommandLineOptions.Instance, RunSettingsManager.Instance, new FileHelper())); } return this.executor; @@ -95,6 +97,7 @@ internal class EnableCodeCoverageArgumentExecutor : IArgumentExecutor private IRunSettingsProvider runSettingsManager; private CommandLineOptions commandLineOptions; + private IFileHelper fileHelper; private const string FriendlyName = "Code Coverage"; @@ -185,10 +188,11 @@ internal class EnableCodeCoverageArgumentExecutor : IArgumentExecutor #endregion - internal EnableCodeCoverageArgumentExecutor(CommandLineOptions options, IRunSettingsProvider runSettingsManager) + internal EnableCodeCoverageArgumentExecutor(CommandLineOptions options, IRunSettingsProvider runSettingsManager, IFileHelper fileHelper) { this.commandLineOptions = options; this.runSettingsManager = runSettingsManager; + this.fileHelper = fileHelper; } /// @@ -242,7 +246,7 @@ private void UpdateWithCodeCoverageSettingsIfNotConfigured() if (ContainsDataCollectorWithFriendlyName(runSettingsNavigator, FriendlyName)) { // runsettings already has Code coverage data collector, just enable it. - CollectArgumentExecutor.AddDataCollectorToRunSettings(FriendlyName, this.runSettingsManager); + CollectArgumentExecutor.AddDataCollectorToRunSettings(FriendlyName, this.runSettingsManager, this.fileHelper); } else { diff --git a/src/vstest.console/Processors/TestAdapterPathArgumentProcessor.cs b/src/vstest.console/Processors/TestAdapterPathArgumentProcessor.cs index 55578503e8..daa64e862d 100644 --- a/src/vstest.console/Processors/TestAdapterPathArgumentProcessor.cs +++ b/src/vstest.console/Processors/TestAdapterPathArgumentProcessor.cs @@ -86,7 +86,7 @@ internal class TestAdapterPathArgumentProcessorCapabilities : BaseArgumentProces public override bool IsAction => false; - public override ArgumentProcessorPriority Priority => ArgumentProcessorPriority.AutoUpdateRunSettings; + public override ArgumentProcessorPriority Priority => ArgumentProcessorPriority.TestAdapterPath; public override string HelpContentResourceName => CommandLineResources.TestAdapterPathHelp; @@ -119,11 +119,11 @@ internal class TestAdapterPathArgumentExecutor : IArgumentExecutor /// For file related operation /// private IFileHelper fileHelper; - + /// /// Separators for multiple paths in argument. /// - private readonly char[] argumentSeparators = new [] { ';' }; + private readonly char[] argumentSeparators = new[] { ';' }; #endregion @@ -168,7 +168,7 @@ public void Initialize(string argument) { 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... @@ -181,9 +181,9 @@ public void Initialize(string argument) { testAdapterPaths.AddRange(SplitPaths(testAdapterPathsInRunSettings)); } - + testAdapterPaths.AddRange(SplitPaths(argument)); - + foreach (var testadapterPath in testAdapterPaths) { // TestAdaptersPaths could contain environment variables diff --git a/src/vstest.console/Processors/Utilities/ArgumentProcessorPriority.cs b/src/vstest.console/Processors/Utilities/ArgumentProcessorPriority.cs index b54592761e..eb14b21b87 100644 --- a/src/vstest.console/Processors/Utilities/ArgumentProcessorPriority.cs +++ b/src/vstest.console/Processors/Utilities/ArgumentProcessorPriority.cs @@ -37,16 +37,16 @@ internal enum ArgumentProcessorPriority VsixExtensions = 5, /// - /// 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 + /// Priority of processors related to Run Settings. /// - TestAdapterPath = 6, + RunSettings = 6, /// - /// Priority of processors related to Run Settings. + /// 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 /// - RunSettings = 10, + TestAdapterPath = 10, /// /// Priority of processors that needs to update runsettings. diff --git a/test/Microsoft.TestPlatform.Common.UnitTests/ExtensionFramework/TestPluginCacheTests.cs b/test/Microsoft.TestPlatform.Common.UnitTests/ExtensionFramework/TestPluginCacheTests.cs index c9da7b9efe..ca12c911d9 100644 --- a/test/Microsoft.TestPlatform.Common.UnitTests/ExtensionFramework/TestPluginCacheTests.cs +++ b/test/Microsoft.TestPlatform.Common.UnitTests/ExtensionFramework/TestPluginCacheTests.cs @@ -149,7 +149,7 @@ public void GetExtensionPathsShouldConsolidateAllExtensions() expectedExtensions.Add("default.dll"); TestPluginCache.Instance.UpdateExtensions(new[] { @"filter.dll" }, false); TestPluginCache.Instance.UpdateExtensions(new[] { @"unfilter.dll" }, true); - TestPluginCache.Instance.DefaultExtensionPaths = new[] {"default.dll"}; + TestPluginCache.Instance.DefaultExtensionPaths = new[] { "default.dll" }; var extensions = TestPluginCache.Instance.GetExtensionPaths("filter.dll"); @@ -163,7 +163,7 @@ public void GetExtensionPathsShouldFilterFilterableExtensions() expectedExtensions.Add("default.dll"); TestPluginCache.Instance.UpdateExtensions(new[] { @"filter.dll", @"other.dll" }, false); TestPluginCache.Instance.UpdateExtensions(new[] { @"unfilter.dll" }, true); - TestPluginCache.Instance.DefaultExtensionPaths = new[] {"default.dll"}; + TestPluginCache.Instance.DefaultExtensionPaths = new[] { "default.dll" }; var extensions = TestPluginCache.Instance.GetExtensionPaths("filter.dll"); @@ -177,7 +177,7 @@ public void GetExtensionPathsShouldNotFilterIfEndsWithPatternIsNullOrEmpty() expectedExtensions.Add("default.dll"); TestPluginCache.Instance.UpdateExtensions(new[] { @"filter.dll", @"other.dll" }, false); TestPluginCache.Instance.UpdateExtensions(new[] { @"unfilter.dll" }, true); - TestPluginCache.Instance.DefaultExtensionPaths = new[] {"default.dll"}; + TestPluginCache.Instance.DefaultExtensionPaths = new[] { "default.dll" }; var extensions = TestPluginCache.Instance.GetExtensionPaths(string.Empty); @@ -459,6 +459,11 @@ protected override IEnumerable GetFilteredExtensions(List extens this.Action?.Invoke(); return extensions; } + + new public void SetupAssemblyResolver(string extensionAssembly) + { + base.SetupAssemblyResolver(extensionAssembly); + } } #endregion diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs index 33f9635197..4b25cbf6e4 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs @@ -302,36 +302,6 @@ public void StartTestRunShouldInitializeExtensionsWithExistingExtensionsOnly() this.mockRequestSender.Verify(s => s.InitializeExecution(expectedOutputPaths), Times.Once); } - [TestMethod] - public void StartTestRunShouldInitializeExtensionsOnlyWithCoverletDataCollectorExtensions() - { - TestPluginCache.Instance = null; - TestPluginCache.Instance.UpdateExtensions(new List { "abc.TestAdapter.dll", "def.TestAdapter.dll", "xyz.TestAdapter.dll", "abc.DataCollector.dll", "xyz.coverlet.collector.dll" }, false); - var expectedOutputPaths = new[] { "abc.TestAdapter.dll", "xyz.TestAdapter.dll", "xyz.coverlet.collector.dll" }; - - this.mockTestHostManager.SetupGet(th => th.Shared).Returns(false); - this.mockRequestSender.Setup(s => s.WaitForRequestHandlerConnection(It.IsAny(), It.IsAny())).Returns(true); - this.mockTestHostManager.Setup(th => th.GetTestPlatformExtensions(It.IsAny>(), It.IsAny>())).Returns((IEnumerable sources, IEnumerable extensions) => - { - return extensions.Select(extension => { return Path.GetFileName(extension); }); - }); - - this.mockFileHelper.Setup(fh => fh.Exists(It.IsAny())).Returns((string extensionPath) => - { - return !extensionPath.Contains("def.TestAdapter.dll"); - }); - - this.mockFileHelper.Setup(fh => fh.Exists("abc.TestAdapter.dll")).Returns(true); - this.mockFileHelper.Setup(fh => fh.Exists("xyz.TestAdapter.dll")).Returns(true); - this.mockFileHelper.Setup(fh => fh.Exists("abc.DataCollector.dll")).Returns(true); - this.mockFileHelper.Setup(fh => fh.Exists("xyz.coverlet.collector.dll")).Returns(true); - - var mockTestRunEventsHandler = new Mock(); - this.testExecutionManager.StartTestRun(this.mockTestRunCriteria.Object, mockTestRunEventsHandler.Object); - - this.mockRequestSender.Verify(s => s.InitializeExecution(expectedOutputPaths), Times.Once); - } - [TestMethod] public void SetupChannelShouldThrowExceptionIfClientConnectionTimeout() { diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/DataCollection/InProcDataCollectorTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/DataCollection/InProcDataCollectorTests.cs index a0fb8316f3..5f9110cd9a 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/DataCollection/InProcDataCollectorTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/DataCollection/InProcDataCollectorTests.cs @@ -6,6 +6,7 @@ namespace TestPlatform.CrossPlatEngine.UnitTests.DataCollection using System.IO; using System.Reflection; using Coverlet.Collector.DataCollection; + using Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection.Interfaces; using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection; @@ -15,6 +16,7 @@ namespace TestPlatform.CrossPlatEngine.UnitTests.DataCollection using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; + using TestPlatform.Common.UnitTests.ExtensionFramework; [TestClass] public class InProcDataCollectorTests @@ -39,7 +41,8 @@ public void InProcDataCollectorShouldNotThrowExceptionIfInvalidAssemblyIsProvide string.Empty, null, string.Empty, - this.assemblyLoadContext.Object); + this.assemblyLoadContext.Object, + TestPluginCache.Instance); Assert.AreEqual(this.inProcDataCollector.AssemblyQualifiedName, null); } @@ -55,7 +58,8 @@ public void InProcDataCollectorShouldNotThrowExceptionIfAssemblyDoesNotContainAn string.Empty, null, string.Empty, - this.assemblyLoadContext.Object); + this.assemblyLoadContext.Object, + TestPluginCache.Instance); Assert.AreEqual(this.inProcDataCollector.AssemblyQualifiedName, null); } @@ -73,7 +77,8 @@ public void InProcDataCollectorShouldInitializeIfAssemblyContainsAnyInProcDataCo typeInfo.AssemblyQualifiedName, typeInfo, string.Empty, - this.assemblyLoadContext.Object); + this.assemblyLoadContext.Object, + TestPluginCache.Instance); Assert.IsNotNull(this.inProcDataCollector.AssemblyQualifiedName); Assert.AreEqual(this.inProcDataCollector.AssemblyQualifiedName, typeInfo.AssemblyQualifiedName); @@ -89,12 +94,19 @@ public void InProcDataCollectorLoadCoverlet() this.assemblyLoadContext.Setup(alc => alc.LoadAssemblyFromPath(It.IsAny())) .Returns(typeInfo.Assembly); + // We need to mock TestPluginCache because we have to create assembly resolver instance + // using SetupAssemblyResolver method, we don't use any other method of class(like DiscoverTestExtensions etc...) + // that fire creation + TestableTestPluginCache testablePlugin = new TestableTestPluginCache(); + testablePlugin.SetupAssemblyResolver(typeInfo.Assembly.Location); + this.inProcDataCollector = new InProcDataCollector( typeInfo.Assembly.Location, "Coverlet.Collector.DataCollection.CoverletInProcDataCollector, coverlet.collector, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", typeof(InProcDataCollection).GetTypeInfo(), string.Empty, - this.assemblyLoadContext.Object); + this.assemblyLoadContext.Object, + testablePlugin); Assert.IsNotNull(this.inProcDataCollector.AssemblyQualifiedName); Assert.AreEqual(this.inProcDataCollector.AssemblyQualifiedName, typeInfo.AssemblyQualifiedName); diff --git a/test/Microsoft.TestPlatform.TestHostProvider.UnitTests/Hosting/DotnetTestHostManagerTests.cs b/test/Microsoft.TestPlatform.TestHostProvider.UnitTests/Hosting/DotnetTestHostManagerTests.cs index 0ebecc7b2b..bac05c8830 100644 --- a/test/Microsoft.TestPlatform.TestHostProvider.UnitTests/Hosting/DotnetTestHostManagerTests.cs +++ b/test/Microsoft.TestPlatform.TestHostProvider.UnitTests/Hosting/DotnetTestHostManagerTests.cs @@ -569,16 +569,6 @@ public void GetTestPlatformExtensionsShouldReturnEmptySetIfSourceDirectoryIsEmpt Assert.AreEqual(0, extensions.Count()); } - [TestMethod] - public void GetTestPlatformExtensionsShouldOnlyAddCoverletDataCollectorsExtensionsIfPresent() - { - this.mockFileHelper.Setup(fh => fh.DirectoryExists(It.IsAny())).Returns(true); - this.mockFileHelper.Setup(fh => fh.EnumerateFiles(It.IsAny(), SearchOption.TopDirectoryOnly, It.IsAny())).Returns(new[] { "foo.dll" }); - var extensions = this.dotnetHostManager.GetTestPlatformExtensions(this.testSource, new List { "coverlet.collector.dll" }); - - Assert.AreEqual(1, extensions.Count()); - } - [TestMethod] public void GetTestPlatformExtensionsShouldNotAddNonCoverletDataCollectorsExtensionsIfPresent() { diff --git a/test/vstest.console.UnitTests/Processors/CollectArgumentProcessorTests.cs b/test/vstest.console.UnitTests/Processors/CollectArgumentProcessorTests.cs index 6083d743c6..7a21b8eef8 100644 --- a/test/vstest.console.UnitTests/Processors/CollectArgumentProcessorTests.cs +++ b/test/vstest.console.UnitTests/Processors/CollectArgumentProcessorTests.cs @@ -9,20 +9,22 @@ namespace vstest.console.UnitTests.Processors using Microsoft.VisualStudio.TestPlatform.CommandLine.Processors; using Microsoft.VisualStudio.TestPlatform.Common; using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces; using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; using static Microsoft.VisualStudio.TestPlatform.CommandLine.Processors.CollectArgumentExecutor; [TestClass] public class CollectArgumentProcessorTests { - private TestableRunSettingsProvider settingsProvider; - private CollectArgumentExecutor executor; - private const string DefaultRunSettings = "\r\n\r\n \r\n {0}\r\n \r\n"; + private readonly TestableRunSettingsProvider settingsProvider; + private readonly CollectArgumentExecutor executor; + private const string DefaultRunSettings = "\r\n\r\n \r\n c:\\AdapterFolderPath\r\n \r\n \r\n {0}\r\n \r\n"; public CollectArgumentProcessorTests() { this.settingsProvider = new TestableRunSettingsProvider(); - this.executor = new CollectArgumentExecutor(this.settingsProvider); + this.executor = new CollectArgumentExecutor(this.settingsProvider, new Mock().Object); CollectArgumentExecutor.EnabledDataCollectors.Clear(); } @@ -120,7 +122,7 @@ public void InitializeShouldCreateEntryForDataCollectorInRunSettingsIfNotAlready this.executor.Initialize("MyDataCollector"); Assert.IsNotNull(this.settingsProvider.ActiveRunSettings); - Assert.AreEqual("\r\n\r\n \r\n \r\n \r\n \r\n \r\n", this.settingsProvider.ActiveRunSettings.SettingsXml); + Assert.AreEqual("\r\n\r\n \r\n c:\\AdapterFolderPath\r\n \r\n \r\n \r\n \r\n \r\n \r\n", this.settingsProvider.ActiveRunSettings.SettingsXml); } [TestMethod] @@ -133,7 +135,7 @@ public void InitializeShouldEnableDataCollectorIfDisabledInRunSettings() this.executor.Initialize("MyDataCollector"); - Assert.AreEqual("\r\n\r\n \r\n \r\n \r\n \r\n \r\n", this.settingsProvider.ActiveRunSettings.SettingsXml); + Assert.AreEqual("\r\n\r\n \r\n c:\\AdapterFolderPath\r\n \r\n \r\n \r\n \r\n \r\n \r\n", this.settingsProvider.ActiveRunSettings.SettingsXml); } [TestMethod] @@ -147,7 +149,7 @@ public void InitializeShouldNotDisableOtherDataCollectorsIfEnabled() this.executor.Initialize("MyDataCollector"); this.executor.Initialize("MyDataCollector2"); - Assert.AreEqual("\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n", this.settingsProvider.ActiveRunSettings.SettingsXml); + Assert.AreEqual("\r\n\r\n \r\n c:\\AdapterFolderPath\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n", this.settingsProvider.ActiveRunSettings.SettingsXml); } [TestMethod] @@ -161,7 +163,7 @@ public void InitializeShouldNotEnableOtherDataCollectorsIfDisabled() this.executor.Initialize("MyDataCollector"); this.executor.Initialize("MyDataCollector2"); - Assert.AreEqual("\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n", this.settingsProvider.ActiveRunSettings.SettingsXml); + Assert.AreEqual("\r\n\r\n \r\n c:\\AdapterFolderPath\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n", this.settingsProvider.ActiveRunSettings.SettingsXml); } [TestMethod] @@ -174,19 +176,51 @@ public void InitializeShouldEnableMultipleCollectorsWhenCalledMoreThanOnce() this.executor.Initialize("MyDataCollector"); this.executor.Initialize("MyDataCollector1"); - Assert.AreEqual("\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n", this.settingsProvider.ActiveRunSettings.SettingsXml); + Assert.AreEqual("\r\n\r\n \r\n c:\\AdapterFolderPath\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n", this.settingsProvider.ActiveRunSettings.SettingsXml); } [TestMethod] public void InitializeShouldAddOutProcAndInprocCollectorWhenXPlatCodeCoverageIsEnabled() - { + { var runsettingsString = string.Format(DefaultRunSettings, string.Empty); var runsettings = new RunSettings(); runsettings.LoadSettingsXml(runsettingsString); this.settingsProvider.SetActiveRunSettings(runsettings); this.executor.Initialize("XPlat Code Coverage"); - Assert.AreEqual($"\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n", this.settingsProvider.ActiveRunSettings.SettingsXml); + Assert.AreEqual($"\r\n\r\n \r\n c:\\AdapterFolderPath\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n", this.settingsProvider.ActiveRunSettings.SettingsXml); + } + + [TestMethod] + public void UpdageXPlatCodeCoverageCodebaseWithFullPathFromTestAdaptersPaths_Found() + { + var runsettingsString = string.Format(DefaultRunSettings, string.Empty); + var runsettings = new RunSettings(); + runsettings.LoadSettingsXml(runsettingsString); + this.settingsProvider.SetActiveRunSettings(runsettings); + Mock fileHelper = new Mock(); + fileHelper.Setup(f => f.Exists(It.IsAny())).Returns(true); + CollectArgumentExecutor executor = new CollectArgumentExecutor(settingsProvider, fileHelper.Object); + executor.Initialize("XPlat Code Coverage"); + executor.Execute(); + + Assert.AreEqual($"\r\n\r\n \r\n c:\\AdapterFolderPath\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n", this.settingsProvider.ActiveRunSettings.SettingsXml); + } + + [TestMethod] + public void UpdageXPlatCodeCoverageCodebaseWithFullPathFromTestAdaptersPaths_NotFound() + { + var runsettingsString = string.Format(DefaultRunSettings, string.Empty); + var runsettings = new RunSettings(); + runsettings.LoadSettingsXml(runsettingsString); + this.settingsProvider.SetActiveRunSettings(runsettings); + Mock fileHelper = new Mock(); + fileHelper.Setup(f => f.Exists(It.IsAny())).Returns(false); + CollectArgumentExecutor executor = new CollectArgumentExecutor(settingsProvider, fileHelper.Object); + executor.Initialize("XPlat Code Coverage"); + executor.Execute(); + + Assert.AreEqual($"\r\n\r\n \r\n c:\\AdapterFolderPath\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n", this.settingsProvider.ActiveRunSettings.SettingsXml); } [TestMethod] diff --git a/test/vstest.console.UnitTests/Processors/EnableBlameArgumentProcessorTests.cs b/test/vstest.console.UnitTests/Processors/EnableBlameArgumentProcessorTests.cs index 99904578d8..4a52ff149c 100644 --- a/test/vstest.console.UnitTests/Processors/EnableBlameArgumentProcessorTests.cs +++ b/test/vstest.console.UnitTests/Processors/EnableBlameArgumentProcessorTests.cs @@ -13,6 +13,7 @@ namespace vstest.console.UnitTests.Processors using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions; using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces; using Microsoft.VisualStudio.TestPlatform.Utilities; + using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using CommandLineResources = Microsoft.VisualStudio.TestPlatform.CommandLine.Resources.Resources; @@ -206,7 +207,7 @@ public void InitializeShouldCreateEntryForBlameAlongWithCollectDumpParametersIfE internal class TestableEnableBlameArgumentExecutor : EnableBlameArgumentExecutor { internal TestableEnableBlameArgumentExecutor(IRunSettingsProvider runSettingsManager, IEnvironment environment, IOutput output) - : base(runSettingsManager, environment) + : base(runSettingsManager, environment, new Mock().Object) { this.Output = output; } diff --git a/test/vstest.console.UnitTests/Processors/EnableCodeCoverageArgumentProcessorTests.cs b/test/vstest.console.UnitTests/Processors/EnableCodeCoverageArgumentProcessorTests.cs index bdf731c510..203578c586 100644 --- a/test/vstest.console.UnitTests/Processors/EnableCodeCoverageArgumentProcessorTests.cs +++ b/test/vstest.console.UnitTests/Processors/EnableCodeCoverageArgumentProcessorTests.cs @@ -7,7 +7,9 @@ namespace vstest.console.UnitTests.Processors using Microsoft.VisualStudio.TestPlatform.CommandLine.Processors; using Microsoft.VisualStudio.TestPlatform.Common; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; + using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces; using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; [TestClass] public class EnableCodeCoverageArgumentProcessorTests @@ -19,7 +21,7 @@ public class EnableCodeCoverageArgumentProcessorTests public EnableCodeCoverageArgumentProcessorTests() { this.settingsProvider = new TestableRunSettingsProvider(); - this.executor = new EnableCodeCoverageArgumentExecutor(CommandLineOptions.Instance, this.settingsProvider); + this.executor = new EnableCodeCoverageArgumentExecutor(CommandLineOptions.Instance, this.settingsProvider, new Mock().Object); CollectArgumentExecutor.EnabledDataCollectors.Clear(); } diff --git a/test/vstest.console.UnitTests/Processors/TestAdapterPathArgumentProcessorTests.cs b/test/vstest.console.UnitTests/Processors/TestAdapterPathArgumentProcessorTests.cs index b8a7d268e1..d81e9f4fdd 100644 --- a/test/vstest.console.UnitTests/Processors/TestAdapterPathArgumentProcessorTests.cs +++ b/test/vstest.console.UnitTests/Processors/TestAdapterPathArgumentProcessorTests.cs @@ -63,7 +63,7 @@ public void CapabilitiesShouldReturnAppropriateProperties() Assert.AreEqual(HelpContentPriority.TestAdapterPathArgumentProcessorHelpPriority, capabilities.HelpPriority); Assert.AreEqual(false, capabilities.IsAction); - Assert.AreEqual(ArgumentProcessorPriority.AutoUpdateRunSettings, capabilities.Priority); + Assert.AreEqual(ArgumentProcessorPriority.TestAdapterPath, capabilities.Priority); Assert.AreEqual(true, capabilities.AllowMultiple); Assert.AreEqual(false, capabilities.AlwaysExecute);