| File: SettingsProvider\SettingsProviderExtensionManager.cs | Web Access |
| Project: src\vstest\src\Microsoft.TestPlatform.Common\Microsoft.TestPlatform.Common.csproj (Microsoft.VisualStudio.TestPlatform.Common) |
// 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; using System.Collections.Generic; using System.Globalization; 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.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; using CommonResources = Microsoft.VisualStudio.TestPlatform.Common.Resources.Resources; using ObjectModelCommonResources = Microsoft.VisualStudio.TestPlatform.ObjectModel.Resources.CommonResources; namespace Microsoft.VisualStudio.TestPlatform.Common.SettingsProvider; /// <summary> /// Manages the settings provider extensions. /// </summary> /// <remarks> /// This is a non-shared instance because we want different settings provider instances to /// be used for each run settings instance. /// </remarks> public class SettingsProviderExtensionManager { private static SettingsProviderExtensionManager? s_settingsProviderExtensionManager; private static readonly object Synclock = new(); /// <summary> /// The settings providers which are available. /// </summary> private readonly IEnumerable<LazyExtension<ISettingsProvider, ISettingsProviderCapabilities>> _settingsProviders; /// <summary> /// Used for logging errors. /// </summary> private readonly IMessageLogger _logger; /// <summary> /// Initializes with the settings providers. /// </summary> /// <remarks> /// The settings providers are imported as non-shared because we need different settings provider /// instances to be used for each run settings. /// </remarks> protected SettingsProviderExtensionManager( IEnumerable<LazyExtension<ISettingsProvider, ISettingsProviderCapabilities>> settingsProviders, IEnumerable<LazyExtension<ISettingsProvider, Dictionary<string, object>>> unfilteredSettingsProviders, IMessageLogger logger) { _settingsProviders = settingsProviders ?? throw new ArgumentNullException(nameof(settingsProviders)); UnfilteredSettingsProviders = unfilteredSettingsProviders ?? throw new ArgumentNullException(nameof(unfilteredSettingsProviders)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); // Populate the map to avoid threading issues SettingsProvidersMap = new Dictionary<string, LazyExtension<ISettingsProvider, ISettingsProviderCapabilities>>(); foreach (var settingsProvider in _settingsProviders) { var settingsName = settingsProvider.Metadata?.SettingsName; if (settingsName is null) { continue; } if (SettingsProvidersMap.ContainsKey(settingsName)) { _logger.SendMessage( TestMessageLevel.Error, string.Format( CultureInfo.CurrentCulture, CommonResources.DuplicateSettingsName, settingsName)); } else { SettingsProvidersMap.Add(settingsName, settingsProvider); } } } /// <summary> /// Gets the Unfiltered list of settings providers. Used for the /ListSettingsProviders command line argument. /// </summary> public IEnumerable<LazyExtension<ISettingsProvider, Dictionary<string, object>>> UnfilteredSettingsProviders { get; } /// <summary> /// Gets the map of settings name to settings provider. /// </summary> public Dictionary<string, LazyExtension<ISettingsProvider, ISettingsProviderCapabilities>> SettingsProvidersMap { get; } /// <summary> /// Creates an instance of the settings provider. /// </summary> /// <returns>Instance of the settings provider.</returns> public static SettingsProviderExtensionManager Create() { if (s_settingsProviderExtensionManager == null) { lock (Synclock) { if (s_settingsProviderExtensionManager == null) { TestPluginManager.GetSpecificTestExtensions<TestSettingsProviderPluginInformation, ISettingsProvider, ISettingsProviderCapabilities, TestSettingsProviderMetadata>( TestPlatformConstants.TestAdapterEndsWithPattern, out var unfilteredTestExtensions, out var testExtensions); s_settingsProviderExtensionManager = new SettingsProviderExtensionManager( testExtensions, unfilteredTestExtensions, TestSessionMessageLogger.Instance); } } } return s_settingsProviderExtensionManager; } /// <summary> /// Destroy the extension manager. /// </summary> public static void Destroy() { lock (Synclock) { s_settingsProviderExtensionManager = null; } } /// <summary> /// Load all the settings provider and fail on error /// </summary> /// <param name="shouldThrowOnError"> Indicates whether this method should throw on error. </param> public static void LoadAndInitializeAllExtensions(bool shouldThrowOnError) { var extensionManager = Create(); foreach (var settingsProvider in extensionManager.SettingsProvidersMap) { try { // Note: - The below Verbose call should not be under IsVerboseEnabled check as we want to // call executor.Value even if logging is not enabled. EqtTrace.Verbose("SettingsProviderExtensionManager: Loading settings provider {0}", settingsProvider.Value.Value); } catch (Exception ex) { // Instantiating one settings provider must not prevent the remaining providers from // being loaded. Log and move on unless the caller opted into failing. EqtTrace.Error("SettingsProviderExtensionManager: LoadAndInitialize: Exception occurred while loading extension {0}: {1}", settingsProvider.Key, ex); if (shouldThrowOnError) { throw; } } } } /// <summary> /// Gets the settings with the provided name. /// </summary> /// <param name="settingsName">Name of the settings to get.</param> /// <returns>Settings provider with the provided name or null if one was not found.</returns> internal LazyExtension<ISettingsProvider, ISettingsProviderCapabilities>? GetSettingsProvider(string settingsName) { if (settingsName.IsNullOrWhiteSpace()) { throw new ArgumentException(ObjectModelCommonResources.CannotBeNullOrEmpty, nameof(settingsName)); } SettingsProvidersMap.TryGetValue(settingsName, out var settingsProvider); return settingsProvider; } } /// <summary> /// Hold data about the Test settings provider. /// </summary> internal class TestSettingsProviderMetadata : ISettingsProviderCapabilities { /// <summary> /// The constructor /// </summary> /// <param name="settingsName">Test settings name</param> public TestSettingsProviderMetadata(string settingsName) { SettingsName = settingsName; } /// <summary> /// Gets test settings name. /// </summary> public string SettingsName { get; private set; } }