Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/Microsoft.TestPlatform.Client/TestPlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,12 @@ private void AddExtensionAssemblies(string runSettings)
continue;
}

var extensionAssemblies = new List<string>(this.fileHelper.EnumerateFiles(adapterPath, SearchOption.AllDirectories, TestPlatformConstants.TestAdapterEndsWithPattern, TestPlatformConstants.TestLoggerEndsWithPattern, TestPlatformConstants.RunTimeEndsWithPattern));
var extensionAssemblies = new List<string>(this.fileHelper.EnumerateFiles(adapterPath, SearchOption.AllDirectories,
TestPlatformConstants.TestAdapterEndsWithPattern,
TestPlatformConstants.TestLoggerEndsWithPattern,
TestPlatformConstants.DataCollectorEndsWithPattern,
TestPlatformConstants.RunTimeEndsWithPattern));

if (extensionAssemblies.Count > 0)
{
this.UpdateExtensions(extensionAssemblies, skipExtensionFilters: false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ private void LogMessage(TestMessageLevel testMessageLevel, string message)
private void InitializeExtensions(IEnumerable<string> sources)
{
var extensions = TestPluginCache.Instance.GetExtensionPaths(TestPlatformConstants.TestAdapterEndsWithPattern, this.skipDefaultAdapters);
extensions = extensions.Concat(TestPluginCache.Instance.GetExtensionPaths(TestPlatformConstants.DataCollectorEndsWithPattern, true)).ToList();

// Filter out non existing extensions
var nonExistingExtensions = extensions.Where(extension => !this.fileHelper.Exists(extension));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection
using System.Linq;
using System.Reflection;
using System.Xml;
using Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework;
using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection.Interfaces;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollector.InProcDataCollector;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.InProcDataCollector;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities;
using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers;
using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces;

/// <summary>
/// The in process data collection extension manager.
Expand All @@ -25,8 +28,14 @@ internal class InProcDataCollectionExtensionManager

private IDataCollectionSink inProcDataCollectionSink;

private const string DataCollectorEndsWithPattern = @"Collector.dll";

private string defaultCodeBase;

private List<string> codeBasePaths;

private IFileHelper fileHelper;

/// <summary>
/// Loaded in-proc datacollectors collection
/// </summary>
Expand All @@ -44,11 +53,24 @@ internal class InProcDataCollectionExtensionManager
/// <param name="defaultCodeBase">
/// The default codebase to be used by inproc data collector
/// </param>
public InProcDataCollectionExtensionManager(string runSettings, ITestEventsPublisher testEventsPublisher, string defaultCodeBase)
public InProcDataCollectionExtensionManager(string runSettings, ITestEventsPublisher testEventsPublisher, string defaultCodeBase, TestPluginCache testPluginCache)
: this(runSettings, testEventsPublisher, defaultCodeBase, testPluginCache, new FileHelper())
{}

protected InProcDataCollectionExtensionManager(string runSettings, ITestEventsPublisher testEventsPublisher, string defaultCodeBase, TestPluginCache testPluginCache, IFileHelper fileHelper)
{
this.InProcDataCollectors = new Dictionary<string, IInProcDataCollector>();
this.inProcDataCollectionSink = new InProcDataCollectionSink();
this.defaultCodeBase = defaultCodeBase;
this.fileHelper = fileHelper;
this.codeBasePaths = new List<string> { this.defaultCodeBase };

// Get Datacollector codebase paths from test plugin cache
var extensionPaths = testPluginCache.GetExtensionPaths(DataCollectorEndsWithPattern);
foreach (var extensionPath in extensionPaths)
{
this.codeBasePaths.Add(Path.GetDirectoryName(extensionPath));
}

// Initialize InProcDataCollectors
this.InitializeInProcDataCollectors(runSettings);
Expand Down Expand Up @@ -215,13 +237,25 @@ private void InitializeInProcDataCollectors(string runSettings)

/// <summary>
/// Gets codebase for inproc datacollector
/// Uses default codebase if given path is not absolute path of inproc datacollector
/// Uses all codebasePaths to check where the datacollector exists
/// </summary>
/// <param name="codeBase">The run Settings.</param>
/// <param name="codeBase">The codebase.</param>
/// <returns> Codebase </returns>
private string GetCodebase(string codeBase)
{
return Path.IsPathRooted(codeBase) ? codeBase : Path.Combine(this.defaultCodeBase, codeBase);
if (!Path.IsPathRooted(codeBase))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: you can flip the condition. if (path.ispathrooted(,....)) { return codebase }

{
foreach (var extensionPath in this.codeBasePaths)
{
var assemblyPath = Path.Combine(extensionPath, codeBase);
if (this.fileHelper.Exists(assemblyPath))
{
return assemblyPath;
}
}
}

return codeBase;
}

private IDictionary<string, object> GetSessionStartProperties(SessionStartEventArgs sessionStartEventArgs)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ private void InitializeDataCollectors(string runSettings, ITestEventsPublisher t
// Initialize inproc data collectors if declared in run settings.
if (XmlRunSettingsUtilities.IsInProcDataCollectionEnabled(runSettings))
{
var inProcDataCollectionExtensionManager = new InProcDataCollectionExtensionManager(runSettings, testEventsPublisher, defaultCodeBase);
var inProcDataCollectionExtensionManager = new InProcDataCollectionExtensionManager(runSettings, testEventsPublisher, defaultCodeBase, TestPluginCache.Instance);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public class DotnetTestHostManager : ITestRuntimeProvider
private const string DotnetTestHostUri = "HostProvider://DotnetTestHost";
private const string DotnetTestHostFriendlyName = "DotnetTestHost";
private const string TestAdapterRegexPattern = @"TestAdapter.dll";
private const string DataCollectorRegexPattern = @"Collector.dll";

private IDotnetHostHelper dotnetHostHelper;

Expand Down Expand Up @@ -238,14 +239,20 @@ public virtual TestProcessStartInfo GetTestHostProcessStartInfo(
/// <inheritdoc/>
public IEnumerable<string> GetTestPlatformExtensions(IEnumerable<string> sources, IEnumerable<string> extensions)
{
List<string> extensionPaths = new List<string>();
var sourceDirectory = Path.GetDirectoryName(sources.Single());

if (!string.IsNullOrEmpty(sourceDirectory) && this.fileHelper.DirectoryExists(sourceDirectory))
{
return this.fileHelper.EnumerateFiles(sourceDirectory, SearchOption.TopDirectoryOnly, TestAdapterRegexPattern);
extensionPaths.AddRange(this.fileHelper.EnumerateFiles(sourceDirectory, SearchOption.TopDirectoryOnly, TestAdapterRegexPattern));
}

return Enumerable.Empty<string>();
if (extensions != null && extensions.Any())
{
extensionPaths.AddRange(extensions.Where(x => x.EndsWith(DataCollectorRegexPattern, StringComparison.OrdinalIgnoreCase)));
}

return extensionPaths;
}

/// <inheritdoc/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ public void StartTestRunShouldInitializeExtensionsIfTestHostIsNotShared()
[TestMethod]
public void StartTestRunShouldInitializeExtensionsWithExistingExtensionsOnly()
{
TestPluginCache.Instance = null;
TestPluginCache.Instance.UpdateExtensions(new List<string> { "abc.TestAdapter.dll", "def.TestAdapter.dll", "xyz.TestAdapter.dll" }, false);
var expectedOutputPaths = new[] { "abc.TestAdapter.dll", "xyz.TestAdapter.dll" };

Expand All @@ -299,7 +300,36 @@ public void StartTestRunShouldInitializeExtensionsWithExistingExtensionsOnly()
this.mockRequestSender.Verify(s => s.InitializeExecution(expectedOutputPaths), Times.Once);
}

[TestMethod]
[TestMethod]
public void StartTestRunShouldInitializeExtensionsWithExistingDataCOllectorExtensions()
{
TestPluginCache.Instance = null;
TestPluginCache.Instance.UpdateExtensions(new List<string> { "abc.TestAdapter.dll", "def.TestAdapter.dll", "xyz.TestAdapter.dll", "abc.DataCollector.dll" }, false);
var expectedOutputPaths = new[] { "abc.TestAdapter.dll", "xyz.TestAdapter.dll", "abc.DataCollector.dll" };

this.mockTestHostManager.SetupGet(th => th.Shared).Returns(false);
this.mockRequestSender.Setup(s => s.WaitForRequestHandlerConnection(It.IsAny<int>(), It.IsAny<CancellationToken>())).Returns(true);
this.mockTestHostManager.Setup(th => th.GetTestPlatformExtensions(It.IsAny<IEnumerable<string>>(), It.IsAny<IEnumerable<string>>())).Returns((IEnumerable<string> sources, IEnumerable<string> extensions) =>
{
return extensions.Select(extension => { return Path.GetFileName(extension); });
});

this.mockFileHelper.Setup(fh => fh.Exists(It.IsAny<string>())).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);

var mockTestRunEventsHandler = new Mock<ITestRunEventsHandler>();
this.testExecutionManager.StartTestRun(this.mockTestRunCriteria.Object, mockTestRunEventsHandler.Object);

this.mockRequestSender.Verify(s => s.InitializeExecution(expectedOutputPaths), Times.Once);
}

[TestMethod]
public void SetupChannelShouldThrowExceptionIfClientConnectionTimeout()
{
this.mockRequestSender.Setup(s => s.WaitForRequestHandlerConnection(It.IsAny<int>(), It.IsAny<CancellationToken>())).Returns(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ namespace TestPlatform.CrossPlatEngine.UnitTests.DataCollection
using System.Linq;
using System.Reflection;
using System.Xml;
using Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework;
using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection;
using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection.Interfaces;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollector.InProcDataCollector;
using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using Moq;
Expand All @@ -37,11 +39,16 @@ public class InProcDataCollectionExtensionManagerTests
private Mock<ITestEventsPublisher> mockTestEventsPublisher;
private TestableInProcDataCollectionExtensionManager inProcDataCollectionManager;
private string defaultCodebase = "E:\\repos\\MSTest\\src\\managed\\TestPlatform\\TestImpactListener.Tests\\bin\\Debug";
private Mock<IFileHelper> mockFileHelper;
private TestPluginCache testPluginCache;

public InProcDataCollectionExtensionManagerTests()
[TestInitialize]
public void TestInit()
{
this.mockTestEventsPublisher = new Mock<ITestEventsPublisher>();
this.inProcDataCollectionManager = new TestableInProcDataCollectionExtensionManager(this.settingsXml, this.mockTestEventsPublisher.Object, this.defaultCodebase);
this.mockFileHelper = new Mock<IFileHelper>();
this.testPluginCache = TestPluginCache.Instance;
this.inProcDataCollectionManager = new TestableInProcDataCollectionExtensionManager(this.settingsXml, this.mockTestEventsPublisher.Object, this.defaultCodebase, this.testPluginCache, this.mockFileHelper.Object);
}

[TestMethod]
Expand All @@ -58,7 +65,7 @@ public void InProcDataCollectionExtensionManagerShouldLoadsDataCollectorsFromRun
}

[TestMethod]
public void InProcDataCollectionExtensionManagerLoadsDataCollectorFromDefaultCodebaseIfCodebaseIsRelative()
public void InProcDataCollectionExtensionManagerLoadsDataCollectorFromDefaultCodebaseIfExistsAndCodebaseIsRelative()
{
string settingsXml = @"<RunSettings>
<InProcDataCollectionRunSettings>
Expand All @@ -71,12 +78,38 @@ public void InProcDataCollectionExtensionManagerLoadsDataCollectorFromDefaultCod
</InProcDataCollectors>
</InProcDataCollectionRunSettings>
</RunSettings>";
this.inProcDataCollectionManager = new TestableInProcDataCollectionExtensionManager(settingsXml, this.mockTestEventsPublisher.Object, this.defaultCodebase);

this.mockFileHelper.Setup(fh => fh.Exists(@"E:\repos\MSTest\src\managed\TestPlatform\TestImpactListener.Tests\bin\Debug\TestImpactListener.Tests.dll")).Returns(true);
this.inProcDataCollectionManager = new TestableInProcDataCollectionExtensionManager(settingsXml, this.mockTestEventsPublisher.Object, this.defaultCodebase, this.testPluginCache, this.mockFileHelper.Object);

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 InProcDataCollectionExtensionManagerLoadsDataCollectorFromTestPluginCacheIfExistsAndCodebaseIsRelative()
{
string settingsXml = @"<RunSettings>
<InProcDataCollectionRunSettings>
<InProcDataCollectors>
<InProcDataCollector friendlyName='Test Impact' uri='InProcDataCollector://Microsoft/TestImpact/1.0' assemblyQualifiedName='TestImpactListener.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=7ccb7239ffde675a' codebase='TestImpactListenerDataCollector.dll'>
<Configuration>
<Port>4312</Port>
</Configuration>
</InProcDataCollector>
</InProcDataCollectors>
</InProcDataCollectionRunSettings>
</RunSettings>";

this.testPluginCache.UpdateExtensions(new List<string> { @"E:\source\.nuget\TestImpactListenerDataCollector.dll" }, true);
this.mockFileHelper.Setup(fh => fh.Exists(@"E:\source\.nuget\TestImpactListenerDataCollector.dll")).Returns(true);

this.inProcDataCollectionManager = new TestableInProcDataCollectionExtensionManager(settingsXml, this.mockTestEventsPublisher.Object, this.defaultCodebase, this.testPluginCache, this.mockFileHelper.Object);

var codebase = (inProcDataCollectionManager.InProcDataCollectors.Values.First() as MockDataCollector).CodeBase;
Assert.AreEqual(codebase, @"E:\source\.nuget\TestImpactListenerDataCollector.dll");
}

[TestMethod]
public void InProcDataCollectionExtensionManagerLoadsDataCollectorFromGivenCodebaseIfCodebaseIsAbsolute()
{
Expand All @@ -91,7 +124,7 @@ public void InProcDataCollectionExtensionManagerLoadsDataCollectorFromGivenCodeb
</InProcDataCollectors>
</InProcDataCollectionRunSettings>
</RunSettings>";
this.inProcDataCollectionManager = new TestableInProcDataCollectionExtensionManager(settingsXml, this.mockTestEventsPublisher.Object, this.defaultCodebase);
this.inProcDataCollectionManager = new TestableInProcDataCollectionExtensionManager(settingsXml, this.mockTestEventsPublisher.Object, this.defaultCodebase, this.testPluginCache, this.mockFileHelper.Object);

var codebase = (inProcDataCollectionManager.InProcDataCollectors.Values.First() as MockDataCollector).CodeBase;
Assert.AreEqual(codebase, "\\\\DummyPath\\TestImpactListener.Tests.dll");
Expand All @@ -117,7 +150,7 @@ public void InProcDataCollectorIsReadingMultipleDataCollector()
</InProcDataCollectionRunSettings>
</RunSettings>";

this.inProcDataCollectionManager = new TestableInProcDataCollectionExtensionManager(multiSettingsXml, this.mockTestEventsPublisher.Object, this.defaultCodebase);
this.inProcDataCollectionManager = new TestableInProcDataCollectionExtensionManager(multiSettingsXml, this.mockTestEventsPublisher.Object, this.defaultCodebase, this.testPluginCache, this.mockFileHelper.Object);
bool secondOne = false;
MockDataCollector dataCollector1 = null;
MockDataCollector dataCollector2 = null;
Expand Down Expand Up @@ -159,7 +192,7 @@ public void InProcDataCollectionExtensionManagerWillNotEnableDataCollectionForIn
</InProcDataCollectionRunSettings>
</RunSettings>";

var manager = new InProcDataCollectionExtensionManager(invalidSettingsXml, this.mockTestEventsPublisher.Object, this.defaultCodebase);
var manager = new InProcDataCollectionExtensionManager(invalidSettingsXml, this.mockTestEventsPublisher.Object, this.defaultCodebase, this.testPluginCache);
Assert.IsFalse(manager.IsInProcDataCollectionEnabled, "InProcDataCollection must be disabled on invalid settings.");
}
[TestMethod]
Expand Down Expand Up @@ -234,7 +267,8 @@ public void TriggerTestCaseEndShouldtBeCalledMultipleTimesInDataDrivenScenario()

internal class TestableInProcDataCollectionExtensionManager : InProcDataCollectionExtensionManager
{
public TestableInProcDataCollectionExtensionManager(string runSettings, ITestEventsPublisher mockTestEventsPublisher, string defaultCodebase) : base(runSettings, mockTestEventsPublisher, defaultCodebase)
public TestableInProcDataCollectionExtensionManager(string runSettings, ITestEventsPublisher mockTestEventsPublisher, string defaultCodebase, TestPluginCache testPluginCache, IFileHelper fileHelper)
: base(runSettings, mockTestEventsPublisher, defaultCodebase, testPluginCache, fileHelper)
{
}

Expand Down
Loading