Skip to content

Commit

Permalink
Complete attachment processors extension
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcoRossignoli committed Nov 23, 2021
1 parent 348a365 commit 823d8fe
Show file tree
Hide file tree
Showing 84 changed files with 3,773 additions and 2,436 deletions.
2 changes: 1 addition & 1 deletion scripts/build/TestPlatform.Dependencies.props
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VSSdkBuildToolsVersion>15.8.3247</VSSdkBuildToolsVersion>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ public void TestRunMessageHandler(object sender, TestRunMessageEventArgs e)
SendTestMessage(e.Level, e.Message);
break;


default:
throw new NotSupportedException($"Test message level '{e.Level}' is not supported.");
}
Expand Down Expand Up @@ -456,7 +456,7 @@ private void StartTestRun(TestRunRequestPayload testRunPayload, ITestRequestMana
this.communicationManager.SendMessage(MessageType.TestMessage, testMessagePayload);
var runCompletePayload = new TestRunCompletePayload()
{
TestRunCompleteArgs = new TestRunCompleteEventArgs(null, false, true, ex, null, TimeSpan.MinValue),
TestRunCompleteArgs = new TestRunCompleteEventArgs(null, false, true, ex, null, null, TimeSpan.MinValue),
LastRunTests = null
};

Expand Down
2 changes: 2 additions & 0 deletions src/Microsoft.TestPlatform.Client/Execution/TestRunRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,7 @@ public void HandleTestRunComplete(TestRunCompleteEventArgs runCompleteArgs, Test
runCompleteArgs.Error,
// This is required as TMI adapter is sending attachments as List which cannot be type casted to Collection.
runContextAttachments != null ? new Collection<AttachmentSet>(runContextAttachments.ToList()) : null,
runCompleteArgs.InvokedDataCollectors,
this.runRequestTimeTracker.Elapsed);

// Ignore the time sent (runCompleteArgs.ElapsedTimeInRunningTests)
Expand Down Expand Up @@ -587,6 +588,7 @@ private void HandleLoggerManagerTestRunComplete(TestRunCompletePayload testRunCo
testRunCompletePayload.TestRunCompleteArgs.IsAborted,
testRunCompletePayload.TestRunCompleteArgs.Error,
testRunCompletePayload.TestRunCompleteArgs.AttachmentSets,
testRunCompletePayload.TestRunCompleteArgs.InvokedDataCollectors,
this.runRequestTimeTracker.Elapsed);
this.LoggerManager.HandleTestRunComplete(testRunCompleteArgs);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,27 @@ public class AfterTestRunEndResult
/// <param name="attachmentSets">
/// The collection of attachment sets.
/// </param>
/// <param name="invokedDataCollectors">
/// The collection of the DataCollectors invoked during test session
/// </param>
/// <param name="metrics">
/// The metrics.
/// </param>
public AfterTestRunEndResult(Collection<AttachmentSet> attachmentSets, IDictionary<string, object> metrics)
public AfterTestRunEndResult(Collection<AttachmentSet> attachmentSets,
Collection<InvokedDataCollector> invokedDataCollectors,
IDictionary<string, object> metrics)
{
this.AttachmentSets = attachmentSets;
this.InvokedDataCollectors = invokedDataCollectors;
this.Metrics = metrics;
}

[DataMember]
public Collection<AttachmentSet> AttachmentSets { get; private set; }

[DataMember]
public Collection<InvokedDataCollector> InvokedDataCollectors { get; private set; }

[DataMember]
public IDictionary<string, object> Metrics { get; private set; }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ namespace Microsoft.VisualStudio.TestPlatform.Common.DataCollector
using System.Linq;
using Microsoft.VisualStudio.TestPlatform.Common.DataCollector.Interfaces;
using Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework;
using Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework.Utilities;
using Microsoft.VisualStudio.TestPlatform.Common.Interfaces;
using Microsoft.VisualStudio.TestPlatform.Common.Logging;
using Microsoft.VisualStudio.TestPlatform.Common.Utilities;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
Expand Down Expand Up @@ -257,6 +259,21 @@ public Collection<AttachmentSet> SessionEnded(bool isCancelled = false)
return new Collection<AttachmentSet>(result);
}

/// <inheritdoc/>
public Collection<InvokedDataCollector> GetInvokedDataCollectors()
{
List<InvokedDataCollector> invokedDataCollector = new List<InvokedDataCollector>();
foreach (DataCollectorInformation dataCollectorInformation in this.RunDataCollectors.Values)
{
invokedDataCollector.Add(new InvokedDataCollector(dataCollectorInformation.DataCollectorConfig.TypeUri,
dataCollectorInformation.DataCollectorConfig.DataCollectorType.AssemblyQualifiedName,
dataCollectorInformation.DataCollectorConfig.FilePath,
dataCollectorInformation.DataCollectorConfig.HasAttachmentsProcessor()));
}

return new Collection<InvokedDataCollector>(invokedDataCollector);
}

/// <inheritdoc/>
public void TestHostLaunched(int processId)
{
Expand Down Expand Up @@ -397,6 +414,29 @@ protected virtual bool TryGetUriFromFriendlyName(string friendlyName, out string
return false;
}

/// <summary>
/// Gets the DataCollectorConfig using uri.
/// </summary>
/// <param name="extensionUri">
/// The extension uri.
/// </param>
/// <returns>
/// The <see cref="DataCollectorConfig"/>.
/// </returns>
protected virtual DataCollectorConfig TryGetDataCollectorConfig(string extensionUri)
{
var extensionManager = this.dataCollectorExtensionManager;
foreach (var extension in extensionManager.TestExtensions)
{
if (string.Equals(extension.TestPluginInfo.IdentifierData, extensionUri, StringComparison.OrdinalIgnoreCase))
{
return (DataCollectorConfig)extension.TestPluginInfo;
}
}

return null;
}

protected virtual bool IsUriValid(string uri)
{
if (string.IsNullOrEmpty(uri))
Expand Down Expand Up @@ -470,7 +510,7 @@ private void LoadAndInitialize(DataCollectorSettings dataCollectorSettings, stri
return;
}

dataCollectorConfig = new DataCollectorConfig(dataCollector.GetType());
dataCollectorConfig = this.TryGetDataCollectorConfig(dataCollectorUri);

// Attempt to get the data collector information verifying that all of the required metadata for the collector is available.
dataCollectorInfo = new DataCollectorInformation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public DataCollectorConfig(Type type)
this.DataCollectorType = type;
this.TypeUri = GetTypeUri(type);
this.FriendlyName = GetFriendlyName(type);
this.AttachmentsProcessorType = GetAttachmentsProcessors(type);
}

/// <summary>
Expand Down Expand Up @@ -63,10 +64,21 @@ public override ICollection<object> Metadata
{
get
{
return new object[] { this.TypeUri.ToString(), this.FriendlyName };
return new object[] { this.TypeUri.ToString(), this.FriendlyName, this.FilePath, this.AttachmentsProcessorType != null };
}
}

/// <summary>
/// Gets attachments processor
/// </summary>
public Type AttachmentsProcessorType { get; private set; }

/// <summary>
/// Check if collector registers an attachement processor.
/// </summary>
/// <returns>True if collector registers an attachment processor.</returns>
public bool HasAttachmentsProcessor() => AttachmentsProcessorType != null;

/// <summary>
/// Gets the Type Uri for the data collector.
/// </summary>
Expand All @@ -88,6 +100,27 @@ private static Uri GetTypeUri(Type dataCollectorType)
return typeUri;
}

/// <summary>
/// Gets the attachment processor for the data collector.
/// </summary>
/// <param name="dataCollectorType">The data collector to get the attachment processor for.</param>
/// <returns>Type of the attachment processor.</returns>
private static Type GetAttachmentsProcessors(Type dataCollectorType)
{
Type attachmentsProcessor = null;
var attachmenstProcessors = GetAttributes(dataCollectorType, typeof(DataCollectorAttachmentProcessorAttribute));
if (attachmenstProcessors != null && attachmenstProcessors.Length > 0)
{
var attachmenstProcessorsAttribute = (DataCollectorAttachmentProcessorAttribute)attachmenstProcessors[0];
if (attachmenstProcessorsAttribute.Type != null)
{
attachmentsProcessor = attachmenstProcessorsAttribute.Type;
}
}

return attachmentsProcessor;
}

/// <summary>
/// Gets the friendly name for the data collector.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,11 @@ internal interface IDataCollectionManager : IDisposable
/// Collection of session attachmentSet.
/// </returns>
Collection<AttachmentSet> SessionEnded(bool isCancelled);

/// <summary>
/// Return a collections of the invoked data collectors
/// </summary>
/// <returns>Collection of data collectors.</returns>
Collection<InvokedDataCollector> GetInvokedDataCollectors();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,35 @@ protected DataCollectorExtensionManager(
/// </returns>
public static DataCollectorExtensionManager Create(IMessageLogger messageLogger)
{

TestPluginManager.Instance.GetSpecificTestExtensions<DataCollectorConfig, DataCollector, IDataCollectorCapabilities, DataCollectorMetadata>(
TestPlatformConstants.DataCollectorEndsWithPattern,
out var unfilteredTestExtensions,
out var filteredTestExtensions);

return new DataCollectorExtensionManager(unfilteredTestExtensions, filteredTestExtensions, messageLogger);
}

/// <summary>
/// Gets an instance of the DataCollectorExtensionManager.
/// </summary>
/// <param name="extensionAssemblyFilePath">
/// File path that contains data collectors to load.
/// </param>
/// <param name="messageLogger">
/// The message Logger.
/// </param>
/// <returns>
/// The DataCollectorExtensionManager.
/// </returns>
public static DataCollectorExtensionManager Create(string extensionAssemblyFilePath, IMessageLogger messageLogger)
{
TestPluginManager.Instance.GetTestExtensions<DataCollectorConfig, DataCollector, IDataCollectorCapabilities, DataCollectorMetadata>(
extensionAssemblyFilePath,
out var unfilteredTestExtensions,
out var filteredTestExtensions);

return new DataCollectorExtensionManager(unfilteredTestExtensions, filteredTestExtensions, messageLogger);
}
}

/// <summary>
Expand All @@ -75,10 +96,12 @@ public class DataCollectorMetadata : IDataCollectorCapabilities
/// <param name="friendlyName">
/// The friendly Name.
/// </param>
public DataCollectorMetadata(string extension, string friendlyName)
public DataCollectorMetadata(string extension, string friendlyName, string filePath, bool hasAttachmentProcessor)
{
this.ExtensionUri = extension;
this.FriendlyName = friendlyName;
this.FilePath = filePath;
this.HasAttachmentProcessor = hasAttachmentProcessor;
}

/// <summary>
Expand All @@ -98,5 +121,23 @@ public string FriendlyName
get;
private set;
}

/// <summary>
/// Check if the data collector has got attachment processor registered
/// </summary>
public bool HasAttachmentProcessor
{
get;
private set;
}

/// <summary>
/// Gets the file path of assemblies that contains the data collector.
/// </summary>
public string FilePath
{
get;
private set;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ internal Dictionary<string, TPluginInfo> GetTestExtensions<TPluginInfo, TExtensi
this.TestExtensions.GetTestExtensionCache<TPluginInfo>(),
extensionAssembly);

if (extensions != null)
if (extensions != null && extensions.Count > 0)
{
return extensions;
}
Expand Down Expand Up @@ -578,6 +578,12 @@ private void LogExtensions()

var loggers = this.TestExtensions.TestLoggers != null ? string.Join(",", this.TestExtensions.TestLoggers.Keys.ToArray()) : null;
EqtTrace.Verbose("TestPluginCache: Loggers are '{0}'.", loggers);

var testhosts = this.TestExtensions.TestHosts != null ? string.Join(",", this.TestExtensions.TestHosts.Keys.ToArray()) : null;
EqtTrace.Verbose("TestPluginCache: TestHosts are '{0}'.", testhosts);

var dataCollectors = this.TestExtensions.DataCollectors != null ? string.Join(",", this.TestExtensions.DataCollectors.Keys.ToArray()) : null;
EqtTrace.Verbose("TestPluginCache: DataCollectors are '{0}'.", dataCollectors);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ namespace Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework
using System.Diagnostics;
using System.Globalization;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;


using Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework.Utilities;
using Microsoft.VisualStudio.TestPlatform.Common.Logging;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
Expand Down Expand Up @@ -130,7 +129,7 @@ private void GetTestExtensionsFromFiles<TPluginInfo, TExtension>(
assembly = Assembly.Load(new AssemblyName(assemblyName));
if (assembly != null)
{
this.GetTestExtensionsFromAssembly<TPluginInfo, TExtension>(assembly, pluginInfos);
this.GetTestExtensionsFromAssembly<TPluginInfo, TExtension>(assembly, pluginInfos, file);
}
}
catch (FileLoadException e)
Expand Down Expand Up @@ -158,7 +157,7 @@ private void GetTestExtensionsFromFiles<TPluginInfo, TExtension>(
/// <typeparam name="TExtension">
/// Type of Extensions.
/// </typeparam>
private void GetTestExtensionsFromAssembly<TPluginInfo, TExtension>(Assembly assembly, Dictionary<string, TPluginInfo> pluginInfos) where TPluginInfo : TestPluginInformation
private void GetTestExtensionsFromAssembly<TPluginInfo, TExtension>(Assembly assembly, Dictionary<string, TPluginInfo> pluginInfos, string filePath) where TPluginInfo : TestPluginInformation
{
Debug.Assert(assembly != null, "null assembly");
Debug.Assert(pluginInfos != null, "null pluginInfos");
Expand Down Expand Up @@ -192,7 +191,7 @@ private void GetTestExtensionsFromAssembly<TPluginInfo, TExtension>(Assembly ass
{
foreach (var type in types)
{
GetTestExtensionFromType(type, extension, pluginInfos);
GetTestExtensionFromType(type, extension, pluginInfos, filePath);
}
}
}
Expand All @@ -215,13 +214,15 @@ private void GetTestExtensionsFromAssembly<TPluginInfo, TExtension>(Assembly ass
private void GetTestExtensionFromType<TPluginInfo>(
Type type,
Type extensionType,
Dictionary<string, TPluginInfo> extensionCollection)
Dictionary<string, TPluginInfo> extensionCollection,
string filePath)
where TPluginInfo : TestPluginInformation
{
if (extensionType.GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()))
{
var rawPluginInfo = Activator.CreateInstance(typeof(TPluginInfo), type);
var pluginInfo = (TPluginInfo)rawPluginInfo;
pluginInfo.FilePath = filePath;

if (pluginInfo == null || pluginInfo.IdentifierData == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,14 @@ public string AssemblyQualifiedName
get;
private set;
}

/// <summary>
/// Gets the file path of the plugin
/// </summary>
public string FilePath
{
get;
internal set;
}
}
}
Loading

0 comments on commit 823d8fe

Please sign in to comment.