Skip to content

Commit

Permalink
Complete the attachment processors extension (#3161)
Browse files Browse the repository at this point in the history
Complete the attachment processors extension
  • Loading branch information
MarcoRossignoli authored Jan 12, 2022
1 parent b1b415c commit 1c9f0fb
Show file tree
Hide file tree
Showing 97 changed files with 4,486 additions and 2,486 deletions.
15 changes: 15 additions & 0 deletions TestPlatform.sln
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestPlatform.Playground", "
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSTest1", "playground\MSTest1\MSTest1.csproj", "{57A61A09-10AD-44BE-8DF4-A6FD108F7DF7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AttachmentProcessorDataCollector", "test\TestAssets\AttachmentProcessorDataCollector\AttachmentProcessorDataCollector.csproj", "{B6AF6BCD-64C6-4F4E-ABCA-C8AA2AA66B7B}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Microsoft.TestPlatform.Execution.Shared\Microsoft.TestPlatform.Execution.Shared.projitems*{10b6ade1-f808-4612-801d-4452f5b52242}*SharedItemsImports = 5
Expand Down Expand Up @@ -868,6 +870,18 @@ Global
{57A61A09-10AD-44BE-8DF4-A6FD108F7DF7}.Release|x64.Build.0 = Release|Any CPU
{57A61A09-10AD-44BE-8DF4-A6FD108F7DF7}.Release|x86.ActiveCfg = Release|Any CPU
{57A61A09-10AD-44BE-8DF4-A6FD108F7DF7}.Release|x86.Build.0 = Release|Any CPU
{B6AF6BCD-64C6-4F4E-ABCA-C8AA2AA66B7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B6AF6BCD-64C6-4F4E-ABCA-C8AA2AA66B7B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B6AF6BCD-64C6-4F4E-ABCA-C8AA2AA66B7B}.Debug|x64.ActiveCfg = Debug|Any CPU
{B6AF6BCD-64C6-4F4E-ABCA-C8AA2AA66B7B}.Debug|x64.Build.0 = Debug|Any CPU
{B6AF6BCD-64C6-4F4E-ABCA-C8AA2AA66B7B}.Debug|x86.ActiveCfg = Debug|Any CPU
{B6AF6BCD-64C6-4F4E-ABCA-C8AA2AA66B7B}.Debug|x86.Build.0 = Debug|Any CPU
{B6AF6BCD-64C6-4F4E-ABCA-C8AA2AA66B7B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B6AF6BCD-64C6-4F4E-ABCA-C8AA2AA66B7B}.Release|Any CPU.Build.0 = Release|Any CPU
{B6AF6BCD-64C6-4F4E-ABCA-C8AA2AA66B7B}.Release|x64.ActiveCfg = Release|Any CPU
{B6AF6BCD-64C6-4F4E-ABCA-C8AA2AA66B7B}.Release|x64.Build.0 = Release|Any CPU
{B6AF6BCD-64C6-4F4E-ABCA-C8AA2AA66B7B}.Release|x86.ActiveCfg = Release|Any CPU
{B6AF6BCD-64C6-4F4E-ABCA-C8AA2AA66B7B}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -942,6 +956,7 @@ Global
{8238A052-D626-49EB-A011-51DC6D0DBA30} = {ED0C35EB-7F31-4841-A24F-8EB708FFA959}
{545A88D3-1AE2-4D39-9B7C-C691768AD17F} = {6CE2F530-582B-4695-A209-41065E103426}
{57A61A09-10AD-44BE-8DF4-A6FD108F7DF7} = {6CE2F530-582B-4695-A209-41065E103426}
{B6AF6BCD-64C6-4F4E-ABCA-C8AA2AA66B7B} = {D9A30E32-D466-4EC5-B4F2-62E17562279B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0541B30C-FF51-4E28-B172-83F5F3934BCD}
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 @@ -14,6 +14,13 @@ namespace Microsoft.VisualStudio.TestPlatform.Common.DataCollection
[DataContract]
public class AfterTestRunEndResult
{
// We have more than one ctor for backward-compatibility reason but we don't want to add dependency on Newtosoft([JsonConstructor])
// We want to fallback to the non-public default constructor https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_ConstructorHandling.htm during deserialization
private AfterTestRunEndResult()
{

}

/// <summary>
/// Initializes a new instance of the <see cref="AfterTestRunEndResult"/> class.
/// </summary>
Expand All @@ -24,14 +31,36 @@ public class AfterTestRunEndResult
/// The metrics.
/// </param>
public AfterTestRunEndResult(Collection<AttachmentSet> attachmentSets, IDictionary<string, object> metrics)
: this(attachmentSets, new Collection<InvokedDataCollector>(), metrics)
{ }

/// <summary>
/// Initializes a new instance of the <see cref="AfterTestRunEndResult"/> class.
/// </summary>
/// <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,
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,22 @@ 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.FriendlyName,
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 +415,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 +511,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.AttachmentsProcessorType != null };
}
}

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

/// <summary>
/// Check if collector registers an attachment 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,39 @@ 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="skipCache">
/// Skip the extensions cache.
/// </param>
/// <param name="messageLogger">
/// The message Logger.
/// </param>
/// <returns>
/// The DataCollectorExtensionManager.
/// </returns>
public static DataCollectorExtensionManager Create(string extensionAssemblyFilePath, bool skipCache, IMessageLogger messageLogger)
{
TestPluginManager.Instance.GetTestExtensions<DataCollectorConfig, DataCollector, IDataCollectorCapabilities, DataCollectorMetadata>(
extensionAssemblyFilePath,
out var unfilteredTestExtensions,
out var filteredTestExtensions,
skipCache);

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

/// <summary>
Expand All @@ -76,9 +101,25 @@ public class DataCollectorMetadata : IDataCollectorCapabilities
/// The friendly Name.
/// </param>
public DataCollectorMetadata(string extension, string friendlyName)
: this(extension, friendlyName, false)
{ }

/// <summary>
/// Constructor for DataCollectorMetadata
/// </summary>
/// <param name="extension">
/// Uri identifying the data collector.
/// </param>
/// <param name="friendlyName">
/// The friendly Name.
/// <param name="hasAttachmentProcessor">
/// Indicates if the current data collector registers an attachment processor
/// </param>
public DataCollectorMetadata(string extension, string friendlyName, bool hasAttachmentProcessor)
{
this.ExtensionUri = extension;
this.FriendlyName = friendlyName;
this.HasAttachmentProcessor = hasAttachmentProcessor;
}

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

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

0 comments on commit 1c9f0fb

Please sign in to comment.