Skip to content

Commit

Permalink
Attachments processors discovery and execution
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcoRossignoli committed Nov 20, 2021
1 parent 348a365 commit 05f6157
Show file tree
Hide file tree
Showing 76 changed files with 3,000 additions and 2,431 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 @@ -94,7 +96,7 @@ protected DataCollectionManager(IDataCollectionAttachmentManager datacollectionA
this.messageSink = messageSink;
this.events = new TestPlatformDataCollectionEvents();
this.dataCollectorExtensionManager = null;
this.RunDataCollectors = new Dictionary<Type, DataCollectorInformation>();
this.InvokedDataCollectors = new Dictionary<Type, DataCollectorInformation>();
this.dataCollectionTelemetryManager = dataCollectionTelemetryManager;
}

Expand All @@ -106,7 +108,7 @@ protected DataCollectionManager(IDataCollectionAttachmentManager datacollectionA
/// <summary>
/// Gets cache of data collectors associated with the run.
/// </summary>
internal Dictionary<Type, DataCollectorInformation> RunDataCollectors { get; private set; }
internal Dictionary<Type, DataCollectorInformation> InvokedDataCollectors { get; private set; }

/// <summary>
/// Gets the data collector extension manager.
Expand Down Expand Up @@ -257,6 +259,24 @@ 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.InvokedDataCollectors.Values)
{
InvokedDataCollector.Add(new InvokedDataCollector()
{
Uri = dataCollectorInformation.DataCollectorConfig.TypeUri,
AssemblyQualifiedName = dataCollectorInformation.DataCollectorConfig.DataCollectorType.AssemblyQualifiedName,
FilePath = dataCollectorInformation.DataCollectorConfig.FilePath,
HasAttachmentProcessor = dataCollectorInformation.DataCollectorConfig.HasAttachmentsProcessor()
});
}

return new Collection<InvokedDataCollector>(InvokedDataCollector);
}

/// <inheritdoc/>
public void TestHostLaunched(int processId)
{
Expand All @@ -274,7 +294,7 @@ public void TestHostLaunched(int processId)
public bool SessionStarted(SessionStartEventArgs sessionStartEventArgs)
{
// If datacollectors are not configured or datacollection is not enabled, return false.
if (!this.isDataCollectionEnabled || this.RunDataCollectors.Count == 0)
if (!this.isDataCollectionEnabled || this.InvokedDataCollectors.Count == 0)
{
return false;
}
Expand Down Expand Up @@ -365,10 +385,10 @@ private void CleanupPlugins()

if (EqtTrace.IsVerboseEnabled)
{
EqtTrace.Verbose("DataCollectionManager.CleanupPlugins: Cleaning up {0} plugins", this.RunDataCollectors.Count);
EqtTrace.Verbose("DataCollectionManager.CleanupPlugins: Cleaning up {0} plugins", this.InvokedDataCollectors.Count);
}

RemoveDataCollectors(new List<DataCollectorInformation>(this.RunDataCollectors.Values));
RemoveDataCollectors(new List<DataCollectorInformation>(this.InvokedDataCollectors.Values));

EqtTrace.Info("DataCollectionManager.CleanupPlugins: CleanupPlugins finished");
}
Expand Down Expand Up @@ -429,6 +449,28 @@ protected virtual DataCollector TryGetTestExtension(string extensionUri)
return this.DataCollectorExtensionManager.TryGetTestExtension(extensionUri).Value;
}

/// <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)
{
foreach (var extension in this.DataCollectorExtensionManager.TestExtensions)
{
if (string.Equals(extension.TestPluginInfo.IdentifierData, extensionUri, StringComparison.OrdinalIgnoreCase))
{
return (DataCollectorConfig)extension.TestPluginInfo;
}
}

return null;
}

/// <summary>
/// Loads and initializes data collector using data collector settings.
/// </summary>
Expand Down Expand Up @@ -464,13 +506,13 @@ private void LoadAndInitialize(DataCollectorSettings dataCollectorSettings, stri
return;
}

if (this.RunDataCollectors.ContainsKey(dataCollector.GetType()))
if (this.InvokedDataCollectors.ContainsKey(dataCollector.GetType()))
{
// Collector is already loaded (may be configured twice). Ignore duplicates and return.
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 Expand Up @@ -498,10 +540,10 @@ private void LoadAndInitialize(DataCollectorSettings dataCollectorSettings, stri
try
{
dataCollectorInfo.InitializeDataCollector();
lock (this.RunDataCollectors)
lock (this.InvokedDataCollectors)
{
// Add data collectors to run cache.
this.RunDataCollectors[dataCollectorConfig.DataCollectorType] = dataCollectorInfo;
this.InvokedDataCollectors[dataCollectorConfig.DataCollectorType] = dataCollectorInfo;
}
}
catch (Exception ex)
Expand Down Expand Up @@ -600,7 +642,7 @@ private Dictionary<string, DataCollectionEnvironmentVariable> GetEnvironmentVari

// Ordering here is temporary to enable Fakes + Code Coverage integration in scenarios when Fakes decides to instrument code using
// CLR Instrumentation Engine. This code will be cleaned when both Fakes and Code Coverage will fully switch to CLR Instrumentation Engine.
foreach (var dataCollectorInfo in this.RunDataCollectors.Values.
foreach (var dataCollectorInfo in this.InvokedDataCollectors.Values.
OrderBy(rdc => rdc.DataCollectorConfig.FriendlyName.Equals(CodeCoverageFriendlyName, StringComparison.OrdinalIgnoreCase) ? 1 : 0))
{
try
Expand Down Expand Up @@ -711,15 +753,15 @@ private void RemoveDataCollectors(IReadOnlyCollection<DataCollectorInformation>
return;
}

lock (this.RunDataCollectors)
lock (this.InvokedDataCollectors)
{
foreach (var dataCollectorToRemove in dataCollectorsToRemove)
{
dataCollectorToRemove.DisposeDataCollector();
this.RunDataCollectors.Remove(dataCollectorToRemove.DataCollector.GetType());
this.InvokedDataCollectors.Remove(dataCollectorToRemove.DataCollector.GetType());
}

if (this.RunDataCollectors.Count == 0)
if (this.InvokedDataCollectors.Count == 0)
{
this.isDataCollectionEnabled = false;
}
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
Loading

0 comments on commit 05f6157

Please sign in to comment.