diff --git a/src/Microsoft.TestPlatform.Common/Interfaces/Engine/ITestCaseEventsHandler.cs b/src/Microsoft.TestPlatform.Common/Interfaces/Engine/ITestCaseEventsHandler.cs index 094a993463..4e27cc48bf 100644 --- a/src/Microsoft.TestPlatform.Common/Interfaces/Engine/ITestCaseEventsHandler.cs +++ b/src/Microsoft.TestPlatform.Common/Interfaces/Engine/ITestCaseEventsHandler.cs @@ -3,6 +3,7 @@ namespace Microsoft.VisualStudio.TestPlatform.ObjectModel.Engine { + using System.Collections.Generic; using Microsoft.VisualStudio.TestPlatform.ObjectModel; /// @@ -33,7 +34,8 @@ public interface ITestCaseEventsHandler /// Send session start event. /// The purpose of this is to perform any initialization before the test case level events are sent. /// - void SendSessionStart(); + /// The session start properties. + void SendSessionStart(IDictionary properties); /// /// Sends session end event. diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/DataCollection/InProcDataCollectionExtensionManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/DataCollection/InProcDataCollectionExtensionManager.cs index ec084cd18d..5c16f9eb3f 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/DataCollection/InProcDataCollectionExtensionManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/DataCollection/InProcDataCollectionExtensionManager.cs @@ -5,11 +5,11 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection { using System; using System.Collections.Generic; + using System.IO; using System.Linq; using System.Reflection; - + using System.Xml; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection.Interfaces; - using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Execution; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection; using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollector.InProcDataCollector; @@ -25,6 +25,8 @@ internal class InProcDataCollectionExtensionManager private IDataCollectionSink inProcDataCollectionSink; + private string defaultCodeBase; + /// /// Loaded in-proc datacollectors collection /// @@ -39,10 +41,14 @@ internal class InProcDataCollectionExtensionManager /// /// The data collection test case event manager. /// - public InProcDataCollectionExtensionManager(string runSettings, ITestEventsPublisher testEventsPublisher) + /// + /// The default codebase to be used by inproc data collector + /// + public InProcDataCollectionExtensionManager(string runSettings, ITestEventsPublisher testEventsPublisher, string defaultCodeBase) { this.InProcDataCollectors = new Dictionary(); this.inProcDataCollectionSink = new InProcDataCollectionSink(); + this.defaultCodeBase = defaultCodeBase; // Initialize InProcDataCollectors this.InitializeInProcDataCollectors(runSettings); @@ -74,13 +80,13 @@ public InProcDataCollectionExtensionManager(string runSettings, ITestEventsPubli /// /// The . /// - protected virtual IInProcDataCollector CreateDataCollector(DataCollectorSettings dataCollectorSettings, TypeInfo interfaceTypeInfo) + protected virtual IInProcDataCollector CreateDataCollector(string assemblyQualifiedName, string codebase, XmlElement configuration, TypeInfo interfaceTypeInfo) { var inProcDataCollector = new InProcDataCollector( - dataCollectorSettings.CodeBase, - dataCollectorSettings.AssemblyQualifiedName, + codebase, + assemblyQualifiedName, interfaceTypeInfo, - dataCollectorSettings.Configuration.OuterXml); + configuration?.OuterXml); inProcDataCollector.LoadDataCollector(this.inProcDataCollectionSink); @@ -98,7 +104,7 @@ protected virtual IInProcDataCollector CreateDataCollector(DataCollectorSettings /// private void TriggerTestSessionStart(object sender, SessionStartEventArgs e) { - TestSessionStartArgs testSessionStartArgs = new TestSessionStartArgs(); + TestSessionStartArgs testSessionStartArgs = new TestSessionStartArgs(this.GetSessionStartProperties(e)); this.TriggerInProcDataCollectionMethods(Constants.TestSessionStartMethodName, testSessionStartArgs); } @@ -172,7 +178,7 @@ private void TriggerUpdateTestResult(object sender, TestResultEventArgs e) private void InitializeInProcDataCollectors(string runSettings) { try - { + { // Check if runsettings contains in-proc datacollector element var inProcDataCollectionRunSettings = XmlRunSettingsUtilities.GetInProcDataCollectionRunSettings(runSettings); var inProcDataCollectionSettingsPresentInRunSettings = inProcDataCollectionRunSettings?.IsCollectionEnabled ?? false; @@ -189,7 +195,10 @@ private void InitializeInProcDataCollectors(string runSettings) var interfaceTypeInfo = typeof(InProcDataCollection).GetTypeInfo(); foreach (var inProcDc in this.inProcDataCollectorSettingsCollection) { - var inProcDataCollector = this.CreateDataCollector(inProcDc, interfaceTypeInfo); + var codeBase = this.GetCodebase(inProcDc.CodeBase); + var assemblyQualifiedName = inProcDc.AssemblyQualifiedName; + var configuration = inProcDc.Configuration; + var inProcDataCollector = this.CreateDataCollector(assemblyQualifiedName, codeBase, configuration, interfaceTypeInfo); this.InProcDataCollectors[inProcDataCollector.AssemblyQualifiedName] = inProcDataCollector; } } @@ -204,6 +213,24 @@ private void InitializeInProcDataCollectors(string runSettings) } } + /// + /// Gets codebase for inproc datacollector + /// Uses default codebase if given path is not absolute path of inproc datacollector + /// + /// The run Settings. + /// Codebase + private string GetCodebase(string codeBase) + { + return Path.IsPathRooted(codeBase) ? codeBase : Path.Combine(this.defaultCodeBase, codeBase); + } + + private IDictionary GetSessionStartProperties(SessionStartEventArgs sessionStartEventArgs) + { + var properties = new Dictionary(); + properties.Add(Constants.TestSourcesPropertyName, sessionStartEventArgs.GetPropertyValue>(Constants.TestSourcesPropertyName)); + return properties; + } + private void TriggerInProcDataCollectionMethods(string methodName, InProcDataCollectionArgs methodArg) { try @@ -263,5 +290,10 @@ internal static class Constants /// The test case end method name. /// public const string TestCaseEndMethodName = "TestCaseEnd"; + + /// + /// Test sources property name + /// + public const string TestSourcesPropertyName = "TestSources"; } } diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/EventHandlers/TestCaseEventsHandler.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/EventHandlers/TestCaseEventsHandler.cs index 790803bb67..9faa970901 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/EventHandlers/TestCaseEventsHandler.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/EventHandlers/TestCaseEventsHandler.cs @@ -4,6 +4,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.EventHandlers { using System; + using System.Collections.Generic; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection.Interfaces; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection; @@ -51,9 +52,9 @@ public void SendTestResult(TestResult result) } /// - public void SendSessionStart() + public void SendSessionStart(IDictionary properties) { - this.SessionStart.SafeInvoke(this, new SessionStartEventArgs(), "TestCaseEventsHandler.RaiseSessionStart"); + this.SessionStart.SafeInvoke(this, new SessionStartEventArgs(properties), "TestCaseEventsHandler.RaiseSessionStart"); } /// diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Execution/BaseRunTests.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Execution/BaseRunTests.cs index d2fb0b2579..6c1e761ada 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Execution/BaseRunTests.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Execution/BaseRunTests.cs @@ -209,7 +209,7 @@ public void RunTests() try { // Call Session-Start event on in-proc datacollectors - this.testCaseEventsHandler?.SendSessionStart(); + this.SendSessionStart(); elapsedTime = this.RunTestsInternal(); @@ -230,7 +230,7 @@ public void RunTests() finally { // Trigger Session End on in-proc datacollectors - this.testCaseEventsHandler?.SendSessionEnd(); + this.SendSessionEnd(); try { @@ -288,6 +288,10 @@ internal void Cancel() protected abstract void InvokeExecutor(LazyExtension executor, Tuple executorUriExtensionTuple, RunContext runContext, IFrameworkHandle frameworkHandle); + protected abstract void SendSessionStart(); + + protected abstract void SendSessionEnd(); + #endregion private void CancelTestRunInternal(ITestExecutor executor) @@ -309,17 +313,6 @@ private void SetContext() { this.testRunCache = new TestRunCache(this.testExecutionContext.FrequencyOfRunStatsChangeEvent, this.testExecutionContext.RunStatsChangeEventTimeout, this.OnCacheHit); - // Initialize data collectors if declared in run settings. - if (DataCollectionTestCaseEventSender.Instance != null && XmlRunSettingsUtilities.IsDataCollectionEnabled(this.runSettings)) - { - var outOfProcDataCollectionManager = new ProxyOutOfProcDataCollectionManager(DataCollectionTestCaseEventSender.Instance, this.testEventsPublisher); - } - - if (XmlRunSettingsUtilities.IsInProcDataCollectionEnabled(this.runSettings)) - { - var inProcDataCollectionExtensionManager = new InProcDataCollectionExtensionManager(this.runSettings, this.testEventsPublisher); - } - this.runContext = new RunContext(); this.runContext.RunSettings = RunSettingsUtilities.CreateAndInitializeRunSettings(this.runSettings); this.runContext.KeepAlive = this.testExecutionContext.KeepAlive; diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Execution/ExecutionManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Execution/ExecutionManager.cs index 815ae614cc..1a526ba435 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Execution/ExecutionManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Execution/ExecutionManager.cs @@ -9,13 +9,18 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Execution using Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework; using Microsoft.VisualStudio.TestPlatform.Common.SettingsProvider; + using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities; using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Tracing; using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Tracing.Interfaces; + using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection; + using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection.Interfaces; + using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Utilities; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Engine; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Engine.ClientProtocol; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Engine.TesthostProtocol; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; /// /// Orchestrates test execution related functionality for the engine communicating with the test host process. @@ -85,6 +90,8 @@ public void StartTestRun( { try { + this.InitializeDataCollectors(runSettings, testCaseEventsHandler as ITestEventsPublisher, TestSourcesUtility.GetDefaultCodebasePath(adapterSourceMap)); + this.activeTestRun = new RunTestsWithSources(this.requestData, adapterSourceMap, package, runSettings, testExecutionContext, testCaseEventsHandler, runEventsHandler); this.activeTestRun.RunTests(); @@ -119,6 +126,8 @@ public void StartTestRun( { try { + this.InitializeDataCollectors(runSettings, testCaseEventsHandler as ITestEventsPublisher, TestSourcesUtility.GetDefaultCodebasePath(tests)); + this.activeTestRun = new RunTestsWithTests(this.requestData, tests, package, runSettings, testExecutionContext, testCaseEventsHandler, runEventsHandler); this.activeTestRun.RunTests(); @@ -196,6 +205,24 @@ private void LoadExtensions() } } + /// + /// Initializes outproc and inproc data collectors. + /// + private void InitializeDataCollectors(string runSettings, ITestEventsPublisher testEventsPublisher, string defaultCodeBase) + { + // Initialize outproc data collectors if declared in run settings. + if (DataCollectionTestCaseEventSender.Instance != null && XmlRunSettingsUtilities.IsDataCollectionEnabled(runSettings)) + { + var outOfProcDataCollectionManager = new ProxyOutOfProcDataCollectionManager(DataCollectionTestCaseEventSender.Instance, testEventsPublisher); + } + + // Initialize inproc data collectors if declared in run settings. + if (XmlRunSettingsUtilities.IsInProcDataCollectionEnabled(runSettings)) + { + var inProcDataCollectionExtensionManager = new InProcDataCollectionExtensionManager(runSettings, testEventsPublisher, defaultCodeBase); + } + } + #endregion } } diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Execution/RunTestsWithSources.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Execution/RunTestsWithSources.cs index 3d0308e087..aca4e83318 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Execution/RunTestsWithSources.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Execution/RunTestsWithSources.cs @@ -15,6 +15,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Execution using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Tracing; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Adapter; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Discovery; + using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Engine; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Engine.ClientProtocol; @@ -30,6 +31,8 @@ internal class RunTestsWithSources : BaseRunTests private Dictionary, IEnumerable> executorUriVsSourceList; + private ITestCaseEventsHandler testCaseEventsHandler; + public RunTestsWithSources(IRequestData requestData, Dictionary> adapterSourceMap, string package, string runSettings, TestExecutionContext testExecutionContext, ITestCaseEventsHandler testCaseEventsHandler, ITestRunEventsHandler testRunEventsHandler) : this(requestData, adapterSourceMap, package, runSettings, testExecutionContext, testCaseEventsHandler, testRunEventsHandler, null) { @@ -52,6 +55,7 @@ internal RunTestsWithSources(IRequestData requestData, Dictionary + /// Sends Session-End event on in-proc datacollectors + /// + protected override void SendSessionEnd() + { + this.testCaseEventsHandler?.SendSessionEnd(); + } + + /// + /// Sends Session-Start event on in-proc datacollectors + /// + protected override void SendSessionStart() + { + // Send session start with test sources in property bag for session start event args. + if (this.testCaseEventsHandler == null) + { + return; + } + + var properties = new Dictionary(); + properties.Add("TestSources", TestSourcesUtility.GetSources(this.adapterSourceMap)); + + this.testCaseEventsHandler.SendSessionStart(properties); + } } } diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Execution/RunTestsWithTests.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Execution/RunTestsWithTests.cs index b189f37fde..52f32507ce 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Execution/RunTestsWithTests.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Execution/RunTestsWithTests.cs @@ -11,6 +11,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Execution using Microsoft.VisualStudio.TestPlatform.Common.Interfaces; using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Tracing; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Adapter; + using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Utilities; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Engine; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Engine.ClientProtocol; @@ -24,6 +25,8 @@ internal class RunTestsWithTests : BaseRunTests private Dictionary, List> executorUriVsTestList; + private ITestCaseEventsHandler testCaseEventsHandler; + public RunTestsWithTests(IRequestData requestData, IEnumerable testCases, string package, string runSettings, TestExecutionContext testExecutionContext, ITestCaseEventsHandler testCaseEventsHandler, ITestRunEventsHandler testRunEventsHandler) : this(requestData, testCases, package, runSettings, testExecutionContext, testCaseEventsHandler, testRunEventsHandler, null) { @@ -45,6 +48,7 @@ internal RunTestsWithTests(IRequestData requestData, IEnumerable testC { this.testCases = testCases; this.executorUriVsTestList = executorUriVsTestList; + this.testCaseEventsHandler = testCaseEventsHandler; } protected override void BeforeRaisingTestRunComplete(bool exceptionsHitDuringRunTests) @@ -67,6 +71,31 @@ protected override void InvokeExecutor(LazyExtension + /// Sends Session-End event on in-proc datacollectors + /// + protected override void SendSessionEnd() + { + this.testCaseEventsHandler?.SendSessionEnd(); + } + + /// + /// Sends Session-Start event on in-proc datacollectors + /// + protected override void SendSessionStart() + { + // Send session start with test sources in property bag for session start event args. + if (this.testCaseEventsHandler == null) + { + return; + } + + var properties = new Dictionary(); + properties.Add("TestSources", TestSourcesUtility.GetSources(this.testCases)); + + this.testCaseEventsHandler.SendSessionStart(properties); + } + /// /// Returns the executor Vs TestCase list /// diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/TestEngine.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/TestEngine.cs index 0c2009a091..e9fb6bc300 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/TestEngine.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/TestEngine.cs @@ -16,6 +16,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client.Parallel; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection; + using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Utilities; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Engine; @@ -313,7 +314,7 @@ private IRequestData GetRequestData(bool isTelemetryOptedIn) /// test sources private IEnumerable GetSourcesFromTestRunCriteria(TestRunCriteria testRunCriteria) { - return testRunCriteria.HasSpecificTests ? testRunCriteria.Tests.Select(tc => tc.Source).Distinct() : testRunCriteria.Sources; + return testRunCriteria.HasSpecificTests ? TestSourcesUtility.GetSources(testRunCriteria.Tests) : testRunCriteria.Sources; } } } diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Utilities/TestSourcesUtility.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Utilities/TestSourcesUtility.cs new file mode 100644 index 0000000000..52d6c337db --- /dev/null +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Utilities/TestSourcesUtility.cs @@ -0,0 +1,59 @@ +// 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.CrossPlatEngine.Utilities +{ + using System.Collections.Generic; + using System.IO; + using System.Linq; + using Microsoft.VisualStudio.TestPlatform.ObjectModel; + + /// + /// Test sources utility class + /// + internal class TestSourcesUtility + { + /// + /// Gets test sources from adapter source map + /// + /// The test list. + /// List of test Sources + internal static IEnumerable GetSources(Dictionary> adapterSourceMap) + { + IEnumerable sources = new List(); + return adapterSourceMap?.Values?.Aggregate(sources, (current, enumerable) => current.Concat(enumerable)); + } + + /// + /// Gets test sources from test case list + /// + /// The test list. + /// List of test Sources + internal static IEnumerable GetSources(IEnumerable tests) + { + return tests?.Select(tc => tc.Source).Distinct(); + } + + /// + /// Gets default code base path for inproc collector from test sources + /// + /// The test list. + /// List of test Sources + internal static string GetDefaultCodebasePath(Dictionary> adapterSourceMap) + { + var source = GetSources(adapterSourceMap)?.FirstOrDefault(); + return source != null ? Path.GetDirectoryName(source) : null; + } + + /// + /// Gets default code base path for inproc collector from test sources + /// + /// The test list. + /// List of test Sources + internal static string GetDefaultCodebasePath(IEnumerable tests) + { + var source = GetSources(tests)?.FirstOrDefault(); + return source != null ? Path.GetDirectoryName(source) : null; + } + } +} diff --git a/src/Microsoft.TestPlatform.ObjectModel/DataCollector/InProcDataCollector/TestSessionStartArgs.cs b/src/Microsoft.TestPlatform.ObjectModel/DataCollector/InProcDataCollector/TestSessionStartArgs.cs index 34ea97329b..1d51764cc9 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/DataCollector/InProcDataCollector/TestSessionStartArgs.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/DataCollector/InProcDataCollector/TestSessionStartArgs.cs @@ -4,12 +4,15 @@ namespace Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollector.InProcDataCollector { using System; + using System.Collections.Generic; /// /// The test session start args. /// public class TestSessionStartArgs : InProcDataCollectionArgs { + private IDictionary Properties; + /// /// Initializes a new instance of the class. /// @@ -18,6 +21,18 @@ public TestSessionStartArgs() this.Configuration = String.Empty; } + /// + /// Initializes a new instance of the class. + /// + /// + /// Properties. + /// + public TestSessionStartArgs(IDictionary properties) + { + this.Configuration = String.Empty; + this.Properties = properties; + } + /// /// Initializes a new instance of the class. /// @@ -33,5 +48,41 @@ public TestSessionStartArgs(string configuration) /// Gets or sets the configuration. /// public string Configuration { get; set; } + + /// + /// Gets session start properties enumerator + /// + public IEnumerator> GetProperties() + { + return this.Properties.GetEnumerator(); + } + + /// + /// Gets property value + /// + /// + /// Property name + /// + public T GetPropertyValue(string property) + { + ValidateArg.NotNullOrEmpty(property, "property"); + + return this.Properties.ContainsKey(property) ? (T)this.Properties[property] : default(T); + } + + /// + /// Gets property value + /// + /// + /// Property name + /// + public object GetPropertyValue(string property) + { + ValidateArg.NotNullOrEmpty(property, "property"); + + this.Properties.TryGetValue(property, out object propertyValue); + + return propertyValue; + } } } diff --git a/src/vstest.console/Processors/CollectArgumentProcessor.cs b/src/vstest.console/Processors/CollectArgumentProcessor.cs index 6eb3454fd2..b7b54e6a67 100644 --- a/src/vstest.console/Processors/CollectArgumentProcessor.cs +++ b/src/vstest.console/Processors/CollectArgumentProcessor.cs @@ -7,7 +7,6 @@ namespace Microsoft.VisualStudio.TestPlatform.CommandLine.Processors using System.Collections.Generic; using System.Globalization; - using Microsoft.VisualStudio.TestPlatform.Common; using Microsoft.VisualStudio.TestPlatform.Common.Interfaces; using Microsoft.VisualStudio.TestPlatform.Common.Utilities; @@ -144,6 +143,32 @@ internal static void EnableDataCollectorUsingFriendlyName(string argument, DataC } } + /// + /// Enables coverlet inproc datacollector + /// + internal static void EnableCoverletInProcDataCollector(string argument, DataCollectionRunSettings dataCollectionRunSettings) + { + DataCollectorSettings dataCollectorSettings = null; + + if (!DoesDataCollectorSettingsExist(argument, dataCollectionRunSettings, out dataCollectorSettings)) + { + // Create a new setting with deafult values + dataCollectorSettings = new DataCollectorSettings(); + dataCollectorSettings.FriendlyName = argument; + dataCollectorSettings.AssemblyQualifiedName = CoverletConstants.CoverletDataCollectorAssemblyQualifiedName; + dataCollectorSettings.CodeBase = CoverletConstants.CoverletDataCollectorCodebase; + dataCollectorSettings.IsEnabled = true; + dataCollectionRunSettings.DataCollectorSettingsList.Add(dataCollectorSettings); + } + else + { + // Set Assembly qualified name and codebase if not already set + dataCollectorSettings.AssemblyQualifiedName = dataCollectorSettings.AssemblyQualifiedName ?? CoverletConstants.CoverletDataCollectorAssemblyQualifiedName; + dataCollectorSettings.CodeBase = dataCollectorSettings.CodeBase ?? CoverletConstants.CoverletDataCollectorCodebase; + dataCollectorSettings.IsEnabled = true; + } + } + private static bool DoesDataCollectorSettingsExist(string friendlyName, DataCollectionRunSettings dataCollectionRunSettings, out DataCollectorSettings dataCollectorSettings) @@ -172,21 +197,49 @@ internal static void AddDataCollectorToRunSettings(string argument, IRunSettings settings = runSettingsManager.ActiveRunSettings?.SettingsXml; } - var dataCollectionRunSettings = XmlRunSettingsUtilities.GetDataCollectionRunSettings(settings); - if (dataCollectionRunSettings == null) - { - dataCollectionRunSettings = new DataCollectionRunSettings(); - } + var dataCollectionRunSettings = XmlRunSettingsUtilities.GetDataCollectionRunSettings(settings) ?? new DataCollectionRunSettings(); + var inProcDataCollectionRunSettings = XmlRunSettingsUtilities.GetInProcDataCollectionRunSettings(settings) + ?? new DataCollectionRunSettings( + Constants.InProcDataCollectionRunSettingsName, + Constants.InProcDataCollectorsSettingName, + Constants.InProcDataCollectorSettingName); // Add data collectors if not already present, enable if already present. EnableDataCollectorUsingFriendlyName(argument, dataCollectionRunSettings); runSettingsManager.UpdateRunSettingsNodeInnerXml(Constants.DataCollectionRunSettingsName, dataCollectionRunSettings.ToXml().InnerXml); + + if (string.Equals(argument, CoverletConstants.CoverletDataCollectorFriendlyName, StringComparison.OrdinalIgnoreCase)) + { + // Add inproc data collector to runsetings if coverlet code coverage is enabled + EnableCoverletInProcDataCollector(argument, inProcDataCollectionRunSettings); + runSettingsManager.UpdateRunSettingsNodeInnerXml(Constants.InProcDataCollectionRunSettingsName, inProcDataCollectionRunSettings.ToXml().InnerXml); + } } internal static void AddDataCollectorFriendlyName(string friendlyName) { EnabledDataCollectors.Add(friendlyName.ToLower()); } + + internal static class CoverletConstants + { + /// + /// Coverlet inproc data collector friendlyname + /// + public const string CoverletDataCollectorFriendlyName = "XPlat Code Coverage"; + + /// TODO : Finalize Name + /// + /// Coverlet inproc data collector assembly qualified name + /// + public const string CoverletDataCollectorAssemblyQualifiedName = "Microsoft.TestPlatform.Extensions.CoverletCoverageDataCollector.CoverletCoverageDataCollector, Microsoft.TestPlatform.Extensions.CoverletCoverageDataCollector, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; + + /// TODO : Finalize codebase + /// + /// Coverlet inproc data collector codebase + /// + public const string CoverletDataCollectorCodebase = "coverletinprocdatacollector.dll"; + } } } diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/DataCollection/InProcDataCollectionExtensionManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/DataCollection/InProcDataCollectionExtensionManagerTests.cs index d05285df0b..88d7aa95a5 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/DataCollection/InProcDataCollectionExtensionManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/DataCollection/InProcDataCollectionExtensionManagerTests.cs @@ -7,10 +7,9 @@ namespace TestPlatform.CrossPlatEngine.UnitTests.DataCollection using System.Collections.Generic; using System.Linq; using System.Reflection; - + using System.Xml; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection.Interfaces; - using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Execution; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection; using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollector.InProcDataCollector; @@ -37,24 +36,65 @@ public class InProcDataCollectionExtensionManagerTests "; private Mock mockTestEventsPublisher; private TestableInProcDataCollectionExtensionManager inProcDataCollectionManager; + private string defaultCodebase = "E:\\repos\\MSTest\\src\\managed\\TestPlatform\\TestImpactListener.Tests\\bin\\Debug"; public InProcDataCollectionExtensionManagerTests() { this.mockTestEventsPublisher = new Mock(); - this.inProcDataCollectionManager = new TestableInProcDataCollectionExtensionManager(this.settingsXml, this.mockTestEventsPublisher.Object); + this.inProcDataCollectionManager = new TestableInProcDataCollectionExtensionManager(this.settingsXml, this.mockTestEventsPublisher.Object, this.defaultCodebase); } [TestMethod] public void InProcDataCollectionExtensionManagerShouldLoadsDataCollectorsFromRunSettings() { - var dataCollectorSettings = (inProcDataCollectionManager.InProcDataCollectors.First().Value as MockDataCollector).DataCollectorSettings; + var dataCollector = inProcDataCollectionManager.InProcDataCollectors.First().Value as MockDataCollector; Assert.IsTrue(inProcDataCollectionManager.IsInProcDataCollectionEnabled, "InProcDataCollection must be enabled if runsettings contains inproc datacollectors."); Assert.AreEqual(inProcDataCollectionManager.InProcDataCollectors.Count, 1, "One Datacollector must be registered"); - Assert.IsTrue(string.Equals(dataCollectorSettings.AssemblyQualifiedName, "TestImpactListener.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=7ccb7239ffde675a", StringComparison.OrdinalIgnoreCase)); - Assert.IsTrue(string.Equals(dataCollectorSettings.CodeBase, @"E:\repos\MSTest\src\managed\TestPlatform\TestImpactListener.Tests\bin\Debug\TestImpactListener.Tests.dll", StringComparison.OrdinalIgnoreCase)); - Assert.IsTrue(string.Equals(dataCollectorSettings.Configuration.OuterXml.ToString(), @"4312", StringComparison.OrdinalIgnoreCase)); + Assert.IsTrue(string.Equals(dataCollector.AssemblyQualifiedName, "TestImpactListener.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=7ccb7239ffde675a", StringComparison.OrdinalIgnoreCase)); + Assert.IsTrue(string.Equals(dataCollector.CodeBase, @"E:\repos\MSTest\src\managed\TestPlatform\TestImpactListener.Tests\bin\Debug\TestImpactListener.Tests.dll", StringComparison.OrdinalIgnoreCase)); + Assert.IsTrue(string.Equals(dataCollector.Configuration.OuterXml.ToString(), @"4312", StringComparison.OrdinalIgnoreCase)); + } + + [TestMethod] + public void InProcDataCollectionExtensionManagerLoadsDataCollectorFromDefaultCodebaseIfCodebaseIsRelative() + { + string settingsXml = @" + + + + + 4312 + + + + + "; + this.inProcDataCollectionManager = new TestableInProcDataCollectionExtensionManager(settingsXml, this.mockTestEventsPublisher.Object, this.defaultCodebase); + + var codebase = (inProcDataCollectionManager.InProcDataCollectors.Values.First() as MockDataCollector).CodeBase; + Assert.AreEqual(codebase, @"E:\repos\MSTest\src\managed\TestPlatform\TestImpactListener.Tests\bin\Debug\TestImpactListener.Tests.dll"); + } + + [TestMethod] + public void InProcDataCollectionExtensionManagerLoadsDataCollectorFromGivenCodebaseIfCodebaseIsAbsolute() + { + string settingsXml = @" + + + + + 4312 + + + + + "; + this.inProcDataCollectionManager = new TestableInProcDataCollectionExtensionManager(settingsXml, this.mockTestEventsPublisher.Object, this.defaultCodebase); + + var codebase = (inProcDataCollectionManager.InProcDataCollectors.Values.First() as MockDataCollector).CodeBase; + Assert.AreEqual(codebase, "\\\\DummyPath\\TestImpactListener.Tests.dll"); } [TestMethod] @@ -77,31 +117,31 @@ public void InProcDataCollectorIsReadingMultipleDataCollector() "; - this.inProcDataCollectionManager = new TestableInProcDataCollectionExtensionManager(multiSettingsXml, this.mockTestEventsPublisher.Object); + this.inProcDataCollectionManager = new TestableInProcDataCollectionExtensionManager(multiSettingsXml, this.mockTestEventsPublisher.Object, this.defaultCodebase); bool secondOne = false; - DataCollectorSettings dataCollectorSettings1 = null; - DataCollectorSettings dataCollectorSettings2 = null; + MockDataCollector dataCollector1 = null; + MockDataCollector dataCollector2 = null; foreach (var inProcDC in inProcDataCollectionManager.InProcDataCollectors.Values) { if (secondOne) { - dataCollectorSettings2 = (inProcDC as MockDataCollector).DataCollectorSettings; + dataCollector2 = inProcDC as MockDataCollector; } else { - dataCollectorSettings1 = (inProcDC as MockDataCollector).DataCollectorSettings; + dataCollector1 = inProcDC as MockDataCollector; secondOne = true; } } - Assert.IsTrue(string.Equals(dataCollectorSettings1.AssemblyQualifiedName, "TestImpactListener.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=7ccb7239ffde675a", StringComparison.OrdinalIgnoreCase)); - Assert.IsTrue(string.Equals(dataCollectorSettings1.CodeBase, @"E:\repos\MSTest\src\managed\TestPlatform\TestImpactListener.Tests\bin\Debug\TestImpactListener.Tests1.dll", StringComparison.OrdinalIgnoreCase)); - Assert.IsTrue(string.Equals(dataCollectorSettings1.Configuration.OuterXml.ToString(), @"4312", StringComparison.OrdinalIgnoreCase)); + Assert.IsTrue(string.Equals(dataCollector1.AssemblyQualifiedName, "TestImpactListener.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=7ccb7239ffde675a", StringComparison.OrdinalIgnoreCase)); + Assert.IsTrue(string.Equals(dataCollector1.CodeBase, @"E:\repos\MSTest\src\managed\TestPlatform\TestImpactListener.Tests\bin\Debug\TestImpactListener.Tests1.dll", StringComparison.OrdinalIgnoreCase)); + Assert.IsTrue(string.Equals(dataCollector1.Configuration.OuterXml.ToString(), @"4312", StringComparison.OrdinalIgnoreCase)); - Assert.IsTrue(string.Equals(dataCollectorSettings2.AssemblyQualifiedName, "TestImpactListener.Tests, Version=2.0.0.0, Culture=neutral, PublicKeyToken=7ccb7239ffde675a", StringComparison.OrdinalIgnoreCase)); - Assert.IsTrue(string.Equals(dataCollectorSettings2.CodeBase, @"E:\repos\MSTest\src\managed\TestPlatform\TestImpactListener.Tests\bin\Debug\TestImpactListener.Tests2.dll", StringComparison.OrdinalIgnoreCase)); - Assert.IsTrue(string.Equals(dataCollectorSettings2.Configuration.OuterXml.ToString(), @"4313", StringComparison.OrdinalIgnoreCase)); + Assert.IsTrue(string.Equals(dataCollector2.AssemblyQualifiedName, "TestImpactListener.Tests, Version=2.0.0.0, Culture=neutral, PublicKeyToken=7ccb7239ffde675a", StringComparison.OrdinalIgnoreCase)); + Assert.IsTrue(string.Equals(dataCollector2.CodeBase, @"E:\repos\MSTest\src\managed\TestPlatform\TestImpactListener.Tests\bin\Debug\TestImpactListener.Tests2.dll", StringComparison.OrdinalIgnoreCase)); + Assert.IsTrue(string.Equals(dataCollector2.Configuration.OuterXml.ToString(), @"4313", StringComparison.OrdinalIgnoreCase)); } [TestMethod] @@ -119,9 +159,24 @@ public void InProcDataCollectionExtensionManagerWillNotEnableDataCollectionForIn "; - var manager = new InProcDataCollectionExtensionManager(invalidSettingsXml, this.mockTestEventsPublisher.Object); + var manager = new InProcDataCollectionExtensionManager(invalidSettingsXml, this.mockTestEventsPublisher.Object, this.defaultCodebase); Assert.IsFalse(manager.IsInProcDataCollectionEnabled, "InProcDataCollection must be disabled on invalid settings."); } + [TestMethod] + public void TriggerSessionStartShouldBeCalledWithCorrectTestSources() + { + var properties = new Dictionary(); + properties.Add("TestSources", new List() { "testsource1.dll", "testsource2.dll" }); + + var mockDataCollector = inProcDataCollectionManager.InProcDataCollectors.Values.FirstOrDefault() as MockDataCollector; + + this.mockTestEventsPublisher.Raise(x => x.SessionStart += null, new SessionStartEventArgs(properties)); + Assert.IsTrue((mockDataCollector.TestSessionStartCalled == 1), "TestSessionStart must be called on datacollector"); + + Assert.IsTrue(mockDataCollector.TestSources.Contains("testsource1.dll")); + Assert.IsTrue(mockDataCollector.TestSources.Contains("testsource2.dll")); + } + [TestMethod] public void TriggerSessionStartShouldCallInProcDataCollector() @@ -179,26 +234,38 @@ public void TriggerTestCaseEndShouldtBeCalledMultipleTimesInDataDrivenScenario() internal class TestableInProcDataCollectionExtensionManager : InProcDataCollectionExtensionManager { - public TestableInProcDataCollectionExtensionManager(string runSettings, ITestEventsPublisher mockTestEventsPublisher) : base(runSettings, mockTestEventsPublisher) + public TestableInProcDataCollectionExtensionManager(string runSettings, ITestEventsPublisher mockTestEventsPublisher, string defaultCodebase) : base(runSettings, mockTestEventsPublisher, defaultCodebase) { } - protected override IInProcDataCollector CreateDataCollector(DataCollectorSettings dataCollectorSettings, TypeInfo interfaceTypeInfo) + protected override IInProcDataCollector CreateDataCollector(string assemblyQualifiedName, string codebase, XmlElement configuration, TypeInfo interfaceTypeInfo) { - return new MockDataCollector(dataCollectorSettings); + return new MockDataCollector(assemblyQualifiedName, codebase,configuration); } } public class MockDataCollector : IInProcDataCollector { - public MockDataCollector(DataCollectorSettings dataCollectorSettings) + public MockDataCollector(string assemblyQualifiedName, string codebase, XmlElement configuration) + { + this.AssemblyQualifiedName = assemblyQualifiedName; + this.CodeBase = codebase; + this.Configuration = configuration; + } + + public string AssemblyQualifiedName { - this.DataCollectorSettings = dataCollectorSettings; + get; + private set; } - public string AssemblyQualifiedName => this.DataCollectorSettings.AssemblyQualifiedName; + public string CodeBase + { + get; + private set; + } - public DataCollectorSettings DataCollectorSettings + public XmlElement Configuration { get; private set; @@ -208,6 +275,11 @@ public DataCollectorSettings DataCollectorSettings public int TestSessionEndCalled { get; private set; } public int TestCaseStartCalled { get; private set; } public int TestCaseEndCalled { get; private set; } + public IEnumerable TestSources + { + get; + private set; + } public void LoadDataCollector(IDataCollectionSink inProcDataCollectionSink) { @@ -218,13 +290,19 @@ public void TriggerInProcDataCollectionMethod(string methodName, InProcDataColle { switch (methodName) { - case Constants.TestSessionStartMethodName: TestSessionStartCalled++; break; + case Constants.TestSessionStartMethodName: this.TestSessionStartMethodCalled(methodArg as TestSessionStartArgs); break; case Constants.TestSessionEndMethodName: TestSessionEndCalled++; break; case Constants.TestCaseStartMethodName: TestCaseStartCalled++; break; case Constants.TestCaseEndMethodName: TestCaseEndCalled++; break; default: break; } } + + private void TestSessionStartMethodCalled(TestSessionStartArgs testSessionStartArgs) + { + TestSessionStartCalled++; + this.TestSources = testSessionStartArgs.GetPropertyValue>("TestSources"); + } } } } diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Execution/BaseRunTestsTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Execution/BaseRunTestsTests.cs index 631b9e99c3..65efe64c15 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Execution/BaseRunTestsTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Execution/BaseRunTestsTests.cs @@ -93,7 +93,7 @@ public BaseRunTestsTests() this.mockTestRunEventsHandler.Object, this.mockTestPlatformEventSource.Object, null, - new PlatformThread(), + new PlatformThread(), this.mockDataSerializer.Object); TestPluginCacheTests.SetupMockExtensions(new string[] { typeof(BaseRunTestsTests).GetTypeInfo().Assembly.Location }, () => { }); @@ -584,7 +584,7 @@ public void RunTestsShouldUpdateActiveTestCasesSourceWithPackageIfTestSourceIsPa const string package = @"C:\Porjects\UnitTestApp3\Debug\UnitTestApp3\UnitTestApp3.build.appxrecipe"; this.mockDataSerializer.Setup(d => d.Clone(It.IsAny())) .Returns(t => JsonDataSerializer.Instance.Clone(t)); - this.SetUpTestRunEvents(package, setupHandleTestRunComplete:false); + this.SetUpTestRunEvents(package, setupHandleTestRunComplete: false); // Act. this.runTestsInstance.RunTests(); @@ -880,7 +880,7 @@ private void SetUpTestRunEvents(string package = null, bool setupHandleTestRunCo this.mockTestRunEventsHandler.Object, this.mockTestPlatformEventSource.Object, null, - new PlatformThread(), + new PlatformThread(), this.mockDataSerializer.Object); var assemblyLocation = typeof(BaseRunTestsTests).GetTypeInfo().Assembly.Location; @@ -978,8 +978,10 @@ public TestableBaseRunTests( platformThread, dataSerializer) { + this.testCaseEventsHandler = testCaseEventsHandler; } + private ITestCaseEventsHandler testCaseEventsHandler; public Action BeforeRaisingTestRunCompleteCallback { get; set; } @@ -1033,6 +1035,16 @@ protected override void InvokeExecutor(LazyExtension { { "TestSources", new List() { "1.dll" } } }); + } } [ExtensionUri(BaseRunTestsExecutorUri)] diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Execution/RunTestsWithSourcesTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Execution/RunTestsWithSourcesTests.cs index d761559f3b..fe552fa4ce 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Execution/RunTestsWithSourcesTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Execution/RunTestsWithSourcesTests.cs @@ -253,6 +253,50 @@ public void RunTestsShouldLogWarningOnNoTestsAvailableInAssemblyWithLongTestCase this.mockTestRunEventsHandler.Verify(treh => treh.HandleLogMessage(TestMessageLevel.Warning, expectedMessage), Times.Once); } + [TestMethod] + public void SendSessionStartShouldCallSessionStartWithCorrectTestSources() + { + var adapterSourceMap = new Dictionary>(); + adapterSourceMap.Add("a", new List { "1.dll", "2.dll" }); + var mockTestCaseEventsHandler = new Mock(); + + this.runTestsInstance = new TestableRunTestsWithSources( + adapterSourceMap, + null, + testExecutionContext, + mockTestCaseEventsHandler.Object, + this.mockTestRunEventsHandler.Object, + this.mockRequestData.Object); + + this.runTestsInstance.CallSendSessionStart(); + + mockTestCaseEventsHandler.Verify(x => x.SendSessionStart(It.Is>( + y => y.ContainsKey("TestSources") + && ((IEnumerable)y["TestSources"]).Contains("1.dll") + && ((IEnumerable)y["TestSources"]).Contains("2.dll") + ))); + } + + [TestMethod] + public void SendSessionEndShouldCallSessionEnd() + { + var adapterSourceMap = new Dictionary>(); + adapterSourceMap.Add("a", new List { "1.dll", "2.dll" }); + var mockTestCaseEventsHandler = new Mock(); + + this.runTestsInstance = new TestableRunTestsWithSources( + adapterSourceMap, + null, + testExecutionContext, + mockTestCaseEventsHandler.Object, + this.mockTestRunEventsHandler.Object, + this.mockRequestData.Object); + + this.runTestsInstance.CallSendSessionEnd(); + + mockTestCaseEventsHandler.Verify(x => x.SendSessionEnd()); + } + private void SetupForNoTestsAvailable(string testCaseFilter, out string sourcesString) { var testAssemblyLocation = typeof(TestCase).GetTypeInfo().Assembly.Location; @@ -305,6 +349,16 @@ public IEnumerable> CallGetExecutorUriExtensionMap( return this.GetExecutorUriExtensionMap(testExecutorFrameworkHandle, runContext); } + public void CallSendSessionStart() + { + this.SendSessionStart(); + } + + public void CallSendSessionEnd() + { + this.SendSessionEnd(); + } + public void CallInvokeExecutor(LazyExtension executor, Tuple executorUriExtensionTuple, RunContext runContext, IFrameworkHandle frameworkHandle) { diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Execution/RunTestsWithTestsTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Execution/RunTestsWithTestsTests.cs index 00177044ed..ee729317c8 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Execution/RunTestsWithTestsTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Execution/RunTestsWithTestsTests.cs @@ -146,6 +146,53 @@ public void InvokeExecutorShouldInvokeTestExecutorWithTheTests() CollectionAssert.AreEqual(tests, receivedTests.ToList()); } + [TestMethod] + public void SendSessionStartShouldCallSessionStartWithCorrectTestSources() + { + var tests = new List + { + new TestCase("A.C.M1", new Uri("e://d"), "s.dll") + }; + var mockTestCaseEventsHandler = new Mock(); + + this.runTestsInstance = new TestableRunTestsWithTests( + tests, + null, + testExecutionContext, + mockTestCaseEventsHandler.Object, + this.mockTestRunEventsHandler.Object, + this.mockRequestData.Object); + + this.runTestsInstance.CallSendSessionStart(); + + mockTestCaseEventsHandler.Verify(x => x.SendSessionStart(It.Is>( + y => y.ContainsKey("TestSources") + && ((IEnumerable)y["TestSources"]).Contains("s.dll") + ))); + } + + [TestMethod] + public void SendSessionEndShouldCallSessionEnd() + { + var tests = new List + { + new TestCase("A.C.M1", new Uri("e://d"), "s.dll") + }; + var mockTestCaseEventsHandler = new Mock(); + + this.runTestsInstance = new TestableRunTestsWithTests( + tests, + null, + testExecutionContext, + mockTestCaseEventsHandler.Object, + this.mockTestRunEventsHandler.Object, + this.mockRequestData.Object); + + this.runTestsInstance.CallSendSessionEnd(); + + mockTestCaseEventsHandler.Verify(x => x.SendSessionEnd()); + } + #region Testable Implemetations private class TestableRunTestsWithTests : RunTestsWithTests @@ -177,6 +224,16 @@ public void CallInvokeExecutor(LazyExtension>(); + adapterSourceMap.Add("adapter1", new List() { "source1.dll", "source2.dll" }); + adapterSourceMap.Add("adapter2", new List() { "source1.dll", "source3.dll" }); + adapterSourceMap.Add("adapter3", new List() { "source1.dll"}); + + var sources = TestSourcesUtility.GetSources(adapterSourceMap); + Assert.AreEqual(sources.Count(), 5); + Assert.IsTrue(sources.Contains("source1.dll")); + Assert.IsTrue(sources.Contains("source2.dll")); + Assert.IsTrue(sources.Contains("source3.dll")); + } + + [TestMethod] + public void GetSourcesShouldGetDistinctSourcesFromTestCases() + { + var tests = new List() { new TestCase("test1", new Uri("e://d"), "source1.dll"), + new TestCase("test2", new Uri("e://d"), "source2.dll"), + new TestCase("test3", new Uri("e://d"), "source1.dll")}; + + var sources = TestSourcesUtility.GetSources(tests); + Assert.AreEqual(sources.Count(), 2); + Assert.IsTrue(sources.Contains("source1.dll")); + Assert.IsTrue(sources.Contains("source2.dll")); + } + + [TestMethod] + public void GetDefaultCodeBasePathShouldReturnNullIfAdapterSourceMapIsEmpty() + { + var adapterSourceMap = new Dictionary>(); + + var defaultCodeBase = TestSourcesUtility.GetDefaultCodebasePath(adapterSourceMap); + Assert.IsNull(defaultCodeBase); + } + + [TestMethod] + public void GetDefaultCodeBasePathShouldReturnNullIfTestCaseListIsEmpty() + { + var tests = new List(); + + var defaultCodeBase = TestSourcesUtility.GetDefaultCodebasePath(tests); + Assert.IsNull(defaultCodeBase); + } + + [TestMethod] + public void GetDefaultCodeBasePathShouldReturnDefaultDirectoryPathForAdapterSourceMap() + { + var adapterSourceMap = new Dictionary>(); + adapterSourceMap.Add("adapter1", new List() { "c:\\folder1\\source1.dll", "c:\\folder2\\source2.dll" }); + + var defaultCodeBase = TestSourcesUtility.GetDefaultCodebasePath(adapterSourceMap); + Assert.AreEqual(defaultCodeBase, "c:\\folder1"); + } + + [TestMethod] + public void GetDefaultCodeBasePathShouldReturnDefaultDirectoryPathForTestCaseList() + { + var tests = new List() { new TestCase("test1", new Uri("e://d"), "c:\\folder1\\source1.dll") }; + + var defaultCodeBase = TestSourcesUtility.GetDefaultCodebasePath(tests); + Assert.AreEqual(defaultCodeBase, "c:\\folder1"); + } + } +} diff --git a/test/vstest.console.UnitTests/Processors/CollectArgumentProcessorTests.cs b/test/vstest.console.UnitTests/Processors/CollectArgumentProcessorTests.cs index ee7eba7fd6..70651d5c97 100644 --- a/test/vstest.console.UnitTests/Processors/CollectArgumentProcessorTests.cs +++ b/test/vstest.console.UnitTests/Processors/CollectArgumentProcessorTests.cs @@ -10,6 +10,7 @@ namespace vstest.console.UnitTests.Processors using Microsoft.VisualStudio.TestPlatform.Common; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestTools.UnitTesting; + using static Microsoft.VisualStudio.TestPlatform.CommandLine.Processors.CollectArgumentExecutor; [TestClass] public class CollectArgumentProcessorTests @@ -176,6 +177,83 @@ public void InitializeShouldEnableMultipleCollectorsWhenCalledMoreThanOnce() Assert.AreEqual("\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); + } + + [TestMethod] + public void InitializeXPlatCodeCoverageShouldNotChangeExistingDataCollectors() + { + var runsettingsString = "\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n"; + runsettingsString = string.Format(runsettingsString, 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 \r\n \r\n \r\n", this.settingsProvider.ActiveRunSettings.SettingsXml); + } + + [TestMethod] + public void InitializeXPlatCodeCoverageShouldNotChangeExistingXPlatDataCollectorSetting() + { + var runsettingsString = "\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n "; + runsettingsString = string.Format(runsettingsString, 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 \r\n \r\n \r\n", this.settingsProvider.ActiveRunSettings.SettingsXml); + } + + [TestMethod] + public void InitializeXPlatCodeCoverageShouldNotChangeExistingXPlatInProcDataCollectorSetting() + { + var runsettingsString = "\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n"; + runsettingsString = string.Format(runsettingsString, 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 \r\n \r\n \r\n", this.settingsProvider.ActiveRunSettings.SettingsXml); + } + + [TestMethod] + public void InitializeXPlatCodeCoverageShouldAddXPlatOutProcProcDataCollectorSetting() + { + var runsettingsString = $"\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n"; + runsettingsString = string.Format(runsettingsString, 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 \r\n \r\n \r\n", this.settingsProvider.ActiveRunSettings.SettingsXml); + } + + [TestMethod] + public void InitializeXPlatCodeCoverageShouldAddXPlatInProcProcDataCollectoPropertiesIfNotPresent() + { + var runsettingsString = $"\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n"; + runsettingsString = string.Format(runsettingsString, 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 \r\n \r\n \r\n", this.settingsProvider.ActiveRunSettings.SettingsXml); + } + #endregion } }