From 67689abb738f3b18251ff264d9e7c4998b4004c7 Mon Sep 17 00:00:00 2001 From: Sanan Yuzbashiyev Date: Thu, 19 Nov 2020 19:07:44 +0100 Subject: [PATCH] TestPluginCache and other dependencies refactoring (#2537) * Small improvements in TestPluginDiscoverer about loading types from assemblies * Small performance improvements * TestExtensions - refactored typeof operations * Added new assembly level attribute to define excat types which should be loaded from that assembly.Removed unnecessary FileHelper instance. * Commenting piece of code which cause build error * Restored previous implementation * Changed methods because previous changes had exception while building in CI * Added missing attribute to blame, event collector and code coverage * Redesigned custom attribute to specify interesting types themselves * More improvements * Fixed cast exception * GetTypes returned to previous implementation and removed unncessary Stopwatch * changed global.json * returned to previous version in global.json * PR review fix --- .../Properties/AssemblyInfo.cs | 3 + .../ExtensionFramework/TestPluginCache.cs | 4 +- .../TestPluginDiscoverer.cs | 58 ++++++-------- .../ExtensionFramework/TestPluginManager.cs | 1 + .../Utilities/TestExtensions.cs | 80 ++++++++++--------- .../Properties/AssemblyInfo.cs | 3 + .../Properties/AssemblyInfo.cs | 27 +++++++ .../Properties/AssemblyInfo.cs | 4 + .../Utilities/TypesToLoadAttribute.cs | 22 +++++ .../Properties/AssemblyInfo.cs | 3 + 10 files changed, 134 insertions(+), 71 deletions(-) create mode 100644 src/Microsoft.TestPlatform.Extensions.HtmlLogger/Properties/AssemblyInfo.cs create mode 100644 src/Microsoft.TestPlatform.ObjectModel/Utilities/TypesToLoadAttribute.cs diff --git a/src/DataCollectors/Microsoft.TestPlatform.Extensions.EventLogCollector/Properties/AssemblyInfo.cs b/src/DataCollectors/Microsoft.TestPlatform.Extensions.EventLogCollector/Properties/AssemblyInfo.cs index d053a05f57..dd4512dc14 100644 --- a/src/DataCollectors/Microsoft.TestPlatform.Extensions.EventLogCollector/Properties/AssemblyInfo.cs +++ b/src/DataCollectors/Microsoft.TestPlatform.Extensions.EventLogCollector/Properties/AssemblyInfo.cs @@ -3,6 +3,8 @@ using System.Reflection; using System.Runtime.InteropServices; +using Microsoft.TestPlatform.Extensions.EventLogCollector; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information @@ -12,6 +14,7 @@ [assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] [assembly: AssemblyProduct("Microsoft.TestPlatform.Extensions.EventLogCollector")] [assembly: AssemblyTrademark("")] +[assembly: TypesToLoad(typeof(EventLogDataCollector))] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from diff --git a/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginCache.cs b/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginCache.cs index a7dc4e04fe..605c1fa8fe 100644 --- a/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginCache.cs +++ b/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginCache.cs @@ -179,10 +179,10 @@ public List GetExtensionPaths(string endsWithPattern, bool skipDefaultEx this.TestExtensions = new TestExtensions(); } - this.TestExtensions.AddExtension(pluginInfos); + this.TestExtensions.AddExtension(pluginInfos); // Set the cache bool to true. - this.TestExtensions.SetTestExtensionsCacheStatus(); + this.TestExtensions.SetTestExtensionsCacheStatusToTrue(); if (EqtTrace.IsVerboseEnabled) { diff --git a/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginDiscoverer.cs b/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginDiscoverer.cs index 5b18dedfb4..3d845df33a 100644 --- a/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginDiscoverer.cs +++ b/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginDiscoverer.cs @@ -4,48 +4,35 @@ namespace Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework { using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Diagnostics.CodeAnalysis; - using System.Globalization; using System.IO; using System.Linq; using System.Reflection; + 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; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; - using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers; - using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces; - using CommonResources = Microsoft.VisualStudio.TestPlatform.Common.Resources.Resources; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; + using CommonResources = Resources.Resources; /// /// Discovers test extensions in a directory. /// internal class TestPluginDiscoverer { - private IFileHelper fileHelper; - - private static List UnloadableFiles = new List(); + private static HashSet UnloadableFiles = new HashSet(); /// /// Initializes a new instance of the class. /// - public TestPluginDiscoverer() : this(new FileHelper()) + public TestPluginDiscoverer() { } - /// - /// Initializes a new instance of the class. - /// - /// - /// The file Helper. - /// - internal TestPluginDiscoverer(IFileHelper fileHelper) - { - this.fileHelper = fileHelper; - } - #region Fields #if WINDOWS_UAP @@ -176,11 +163,20 @@ private void AddKnownExtensions(ref IEnumerable extensionPaths) { Debug.Assert(assembly != null, "null assembly"); Debug.Assert(pluginInfos != null, "null pluginInfos"); - Type[] types; + IEnumerable types; + Type extension = typeof(TExtension); try - { - types = assembly.GetTypes(); + { + var customAttribute = CustomAttributeExtensions.GetCustomAttribute(assembly, typeof(TypesToLoadAttribute)) as TypesToLoadAttribute; + if (customAttribute != null) + { + types = customAttribute.Types; + } + else + { + types = assembly.GetTypes().Where(type => type.GetTypeInfo().IsClass && !type.GetTypeInfo().IsAbstract); + } } catch (ReflectionTypeLoadException e) { @@ -196,14 +192,11 @@ private void AddKnownExtensions(ref IEnumerable extensionPaths) return; } - if ((types != null) && (types.Length > 0)) + if (types != null && types.Any()) { foreach (var type in types) { - if (type.GetTypeInfo().IsClass && !type.GetTypeInfo().IsAbstract) - { - this.GetTestExtensionFromType(type, typeof(TExtension), pluginInfos); - } + GetTestExtensionFromType(type, extension, pluginInfos); } } } @@ -241,15 +234,14 @@ private void AddKnownExtensions(ref IEnumerable extensionPaths) EqtTrace.Error( "TryGetTestExtensionFromType: Either PluginInformation is null or PluginInformation doesn't contain IdentifierData for type {0}.", type.FullName); } - return; } if (extensionCollection.ContainsKey(pluginInfo.IdentifierData)) { EqtTrace.Warning( - "TryGetTestExtensionFromType: Discovered multiple test extensions with identifier data '{0}'; keeping the first one.", - pluginInfo.IdentifierData); + "TryGetTestExtensionFromType: Discovered multiple test extensions with identifier data '{0}'; keeping the first one.", + pluginInfo.IdentifierData); } else { diff --git a/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginManager.cs b/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginManager.cs index b322d75fd7..ae780aa7a3 100644 --- a/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginManager.cs +++ b/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginManager.cs @@ -5,6 +5,7 @@ namespace Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework { using System; using System.Collections.Generic; + using System.Diagnostics; using System.Reflection; using Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework.Utilities; diff --git a/src/Microsoft.TestPlatform.Common/ExtensionFramework/Utilities/TestExtensions.cs b/src/Microsoft.TestPlatform.Common/ExtensionFramework/Utilities/TestExtensions.cs index 7ad4ddede3..ea0a52a4f5 100644 --- a/src/Microsoft.TestPlatform.Common/ExtensionFramework/Utilities/TestExtensions.cs +++ b/src/Microsoft.TestPlatform.Common/ExtensionFramework/Utilities/TestExtensions.cs @@ -147,31 +147,31 @@ internal TestExtensions GetExtensionsDiscoveredFromAssembly(string extensionAsse var testExtensions = new TestExtensions(); testExtensions.TestDiscoverers = - this.GetExtensionsDiscoveredFromAssembly( + this.GetExtensionsDiscoveredFromAssembly( this.TestDiscoverers, extensionAssembly); testExtensions.TestExecutors = - this.GetExtensionsDiscoveredFromAssembly( + this.GetExtensionsDiscoveredFromAssembly( this.TestExecutors, extensionAssembly); testExtensions.TestExecutors2 = - this.GetExtensionsDiscoveredFromAssembly( + this.GetExtensionsDiscoveredFromAssembly( this.TestExecutors2, extensionAssembly); testExtensions.TestSettingsProviders = - this.GetExtensionsDiscoveredFromAssembly( + this.GetExtensionsDiscoveredFromAssembly( this.TestSettingsProviders, extensionAssembly); testExtensions.TestLoggers = - this.GetExtensionsDiscoveredFromAssembly( + this.GetExtensionsDiscoveredFromAssembly( this.TestLoggers, extensionAssembly); testExtensions.TestHosts = - this.GetExtensionsDiscoveredFromAssembly( + this.GetExtensionsDiscoveredFromAssembly( this.TestHosts, extensionAssembly); testExtensions.DataCollectors = - this.GetExtensionsDiscoveredFromAssembly( + this.GetExtensionsDiscoveredFromAssembly( this.DataCollectors, extensionAssembly); @@ -192,31 +192,33 @@ internal TestExtensions GetExtensionsDiscoveredFromAssembly(string extensionAsse internal Dictionary GetTestExtensionCache() where TPluginInfo : TestPluginInformation { - if (typeof(TPluginInfo) == typeof(TestDiscovererPluginInformation)) + Type type = typeof(TPluginInfo); + + if (type == typeof(TestDiscovererPluginInformation)) { return (Dictionary)(object)this.TestDiscoverers; } - else if (typeof(TPluginInfo) == typeof(TestExecutorPluginInformation)) + else if (type == typeof(TestExecutorPluginInformation)) { return (Dictionary)(object)this.TestExecutors; } - else if (typeof(TPluginInfo) == typeof(TestExecutorPluginInformation2)) + else if (type == typeof(TestExecutorPluginInformation2)) { return (Dictionary)(object)this.TestExecutors2; } - else if (typeof(TPluginInfo) == typeof(TestLoggerPluginInformation)) + else if (type == typeof(TestLoggerPluginInformation)) { return (Dictionary)(object)this.TestLoggers; } - else if (typeof(TPluginInfo) == typeof(TestSettingsProviderPluginInformation)) + else if (type == typeof(TestSettingsProviderPluginInformation)) { return (Dictionary)(object)this.TestSettingsProviders; } - else if (typeof(TPluginInfo) == typeof(TestRuntimePluginInformation)) + else if (type == typeof(TestRuntimePluginInformation)) { return (Dictionary)(object)this.TestHosts; } - else if (typeof(TPluginInfo) == typeof(DataCollectorConfig)) + else if (type == typeof(DataCollectorConfig)) { return (Dictionary)(object)this.DataCollectors; } @@ -234,31 +236,33 @@ internal TestExtensions GetExtensionsDiscoveredFromAssembly(string extensionAsse /// internal bool AreTestExtensionsCached() where TPluginInfo : TestPluginInformation { - if (typeof(TPluginInfo) == typeof(TestDiscovererPluginInformation)) + Type type = typeof(TPluginInfo); + + if (type == typeof(TestDiscovererPluginInformation)) { return this.AreTestDiscoverersCached; } - else if (typeof(TPluginInfo) == typeof(TestExecutorPluginInformation)) + else if (type == typeof(TestExecutorPluginInformation)) { return this.AreTestExecutorsCached; } - else if (typeof(TPluginInfo) == typeof(TestExecutorPluginInformation2)) + else if (type == typeof(TestExecutorPluginInformation2)) { return this.AreTestExecutors2Cached; } - else if (typeof(TPluginInfo) == typeof(TestLoggerPluginInformation)) + else if (type == typeof(TestLoggerPluginInformation)) { return this.AreTestLoggersCached; } - else if (typeof(TPluginInfo) == typeof(TestSettingsProviderPluginInformation)) + else if (type == typeof(TestSettingsProviderPluginInformation)) { return this.AreTestSettingsProvidersCached; } - else if (typeof(TPluginInfo) == typeof(TestRuntimePluginInformation)) + else if (type == typeof(TestRuntimePluginInformation)) { return this.AreTestHostsCached; } - else if (typeof(TPluginInfo) == typeof(DataCollectorConfig)) + else if (type == typeof(DataCollectorConfig)) { return this.AreDataCollectorsCached; } @@ -271,33 +275,35 @@ internal TestExtensions GetExtensionsDiscoveredFromAssembly(string extensionAsse /// /// /// - internal void SetTestExtensionsCacheStatus() where TPluginInfo : TestPluginInformation + internal void SetTestExtensionsCacheStatusToTrue() where TPluginInfo : TestPluginInformation { - if (typeof(TPluginInfo) == typeof(TestDiscovererPluginInformation)) + Type type = typeof(TPluginInfo); + + if (type == typeof(TestDiscovererPluginInformation)) { this.AreTestDiscoverersCached = true; } - else if (typeof(TPluginInfo) == typeof(TestExecutorPluginInformation)) + else if (type == typeof(TestExecutorPluginInformation)) { this.AreTestExecutorsCached = true; } - else if (typeof(TPluginInfo) == typeof(TestExecutorPluginInformation2)) + else if (type == typeof(TestExecutorPluginInformation2)) { this.AreTestExecutors2Cached = true; } - else if (typeof(TPluginInfo) == typeof(TestLoggerPluginInformation)) + else if (type == typeof(TestLoggerPluginInformation)) { this.AreTestLoggersCached = true; } - else if (typeof(TPluginInfo) == typeof(TestSettingsProviderPluginInformation)) + else if (type == typeof(TestSettingsProviderPluginInformation)) { this.AreTestSettingsProvidersCached = true; } - else if (typeof(TPluginInfo) == typeof(TestRuntimePluginInformation)) + else if (type == typeof(TestRuntimePluginInformation)) { this.AreTestHostsCached = true; } - else if (typeof(TPluginInfo) == typeof(DataCollectorConfig)) + else if (type == typeof(DataCollectorConfig)) { this.AreDataCollectorsCached = true; } @@ -358,31 +364,33 @@ internal void InvalidateCache() private void SetTestExtensionCache(Dictionary testPluginInfos) where TPluginInfo : TestPluginInformation { - if (typeof(TPluginInfo) == typeof(TestDiscovererPluginInformation)) + Type type = typeof(TPluginInfo); + + if (type == typeof(TestDiscovererPluginInformation)) { this.TestDiscoverers = (Dictionary)(object)testPluginInfos; } - else if (typeof(TPluginInfo) == typeof(TestExecutorPluginInformation)) + else if (type == typeof(TestExecutorPluginInformation)) { this.TestExecutors = (Dictionary)(object)testPluginInfos; } - else if (typeof(TPluginInfo) == typeof(TestExecutorPluginInformation2)) + else if (type == typeof(TestExecutorPluginInformation2)) { this.TestExecutors2 = (Dictionary)(object)testPluginInfos; } - else if (typeof(TPluginInfo) == typeof(TestLoggerPluginInformation)) + else if (type == typeof(TestLoggerPluginInformation)) { this.TestLoggers = (Dictionary)(object)testPluginInfos; } - else if (typeof(TPluginInfo) == typeof(TestSettingsProviderPluginInformation)) + else if (type == typeof(TestSettingsProviderPluginInformation)) { this.TestSettingsProviders = (Dictionary)(object)testPluginInfos; } - else if (typeof(TPluginInfo) == typeof(TestRuntimePluginInformation)) + else if (type == typeof(TestRuntimePluginInformation)) { this.TestHosts = (Dictionary)(object)testPluginInfos; } - else if (typeof(TPluginInfo) == typeof(DataCollectorConfig)) + else if (type == typeof(DataCollectorConfig)) { this.DataCollectors = (Dictionary)(object)testPluginInfos; } diff --git a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Properties/AssemblyInfo.cs b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Properties/AssemblyInfo.cs index 33717a5453..68809aec87 100644 --- a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Properties/AssemblyInfo.cs +++ b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Properties/AssemblyInfo.cs @@ -3,6 +3,8 @@ using System.Reflection; using System.Runtime.InteropServices; +using Microsoft.TestPlatform.Extensions.BlameDataCollector; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information @@ -12,6 +14,7 @@ [assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] [assembly: AssemblyProduct("Microsoft.TestPlatform.Extensions.BlameDataCollector")] [assembly: AssemblyTrademark("")] +[assembly: TypesToLoad(typeof(BlameLogger), typeof(BlameCollector))] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from diff --git a/src/Microsoft.TestPlatform.Extensions.HtmlLogger/Properties/AssemblyInfo.cs b/src/Microsoft.TestPlatform.Extensions.HtmlLogger/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..bc64c4ba85 --- /dev/null +++ b/src/Microsoft.TestPlatform.Extensions.HtmlLogger/Properties/AssemblyInfo.cs @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using System.Runtime.InteropServices; +using Microsoft.VisualStudio.TestPlatform.Extensions.HtmlLogger; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft Corporation")] +[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] +[assembly: AssemblyProduct("Microsoft.TestPlatform.Extensions.HtmlLogger")] +[assembly: AssemblyTrademark("")] +[assembly: TypesToLoad(typeof(HtmlLogger))] + + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM. + +[assembly: Guid("1f26e9c7-5018-4091-a22a-89280f2f98a9")] diff --git a/src/Microsoft.TestPlatform.Extensions.TrxLogger/Properties/AssemblyInfo.cs b/src/Microsoft.TestPlatform.Extensions.TrxLogger/Properties/AssemblyInfo.cs index f2b2307987..57f3f4ab80 100644 --- a/src/Microsoft.TestPlatform.Extensions.TrxLogger/Properties/AssemblyInfo.cs +++ b/src/Microsoft.TestPlatform.Extensions.TrxLogger/Properties/AssemblyInfo.cs @@ -3,6 +3,8 @@ using System.Reflection; using System.Runtime.InteropServices; +using Microsoft.VisualStudio.TestPlatform.Extensions.TrxLogger; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information @@ -12,6 +14,8 @@ [assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] [assembly: AssemblyProduct("Microsoft.TestPlatform.Extensions.TrxLogger")] [assembly: AssemblyTrademark("")] +[assembly: TypesToLoad(typeof(TrxLogger))] + // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from diff --git a/src/Microsoft.TestPlatform.ObjectModel/Utilities/TypesToLoadAttribute.cs b/src/Microsoft.TestPlatform.ObjectModel/Utilities/TypesToLoadAttribute.cs new file mode 100644 index 0000000000..5f8824b510 --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Utilities/TypesToLoadAttribute.cs @@ -0,0 +1,22 @@ +// 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.ObjectModel.Utilities +{ + using System; + + /// + /// Custom Attribute to specify the exact types which should be loaded from assembly + /// + [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] + [CLSCompliant(false)] + public sealed class TypesToLoadAttribute : Attribute + { + public TypesToLoadAttribute(params Type[] types) + { + Types = types; + } + + public Type[] Types { get; } + } +} diff --git a/src/Microsoft.TestPlatform.TestHostProvider/Properties/AssemblyInfo.cs b/src/Microsoft.TestPlatform.TestHostProvider/Properties/AssemblyInfo.cs index 892e0ae7e4..cfcaf11468 100644 --- a/src/Microsoft.TestPlatform.TestHostProvider/Properties/AssemblyInfo.cs +++ b/src/Microsoft.TestPlatform.TestHostProvider/Properties/AssemblyInfo.cs @@ -3,6 +3,8 @@ using System.Reflection; using System.Runtime.InteropServices; +using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Hosting; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information @@ -12,6 +14,7 @@ [assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] [assembly: AssemblyProduct("Microsoft.TestPlatform.TestHostRuntimeProvider")] [assembly: AssemblyTrademark("")] +[assembly: TypesToLoad(typeof(DefaultTestHostManager), typeof(DotnetTestHostManager))] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from