// 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.ComponentModel; using Microsoft.Testing.Platform.Capabilities.TestFramework; using Microsoft.Testing.Platform.CommandLine; using Microsoft.Testing.Platform.Configurations; using Microsoft.Testing.Platform.Extensions.TestFramework; using Microsoft.Testing.Platform.Extensions.TestHostControllers; using Microsoft.Testing.Platform.Helpers; using Microsoft.Testing.Platform.IPC; using Microsoft.Testing.Platform.Logging; using Microsoft.Testing.Platform.Messages; using Microsoft.Testing.Platform.OutputDevice; using Microsoft.Testing.Platform.Requests; using Microsoft.Testing.Platform.Resources; using Microsoft.Testing.Platform.Telemetry; using Microsoft.Testing.Platform.TestHostControllers; namespace Microsoft.Testing.Platform.Services; /// /// Extension methods for getting services from an . /// public static class ServiceProviderExtensions { /// /// Gets the required service of type from the . /// /// The type of the service. /// The service provider. /// The required service of type . /// Thrown when the is null. /// Thrown when the required service is not found. public static TService GetRequiredService(this IServiceProvider provider) where TService : notnull => provider.GetRequiredPlatformService(); /// /// Gets the required Microsoft Testing Platform service of type /// from the . /// /// The type of the platform service. /// The service provider. /// The required platform service of type . /// Thrown when the is null. /// Thrown when the required service is not found. /// /// Prefer this method when the project also references Microsoft.Extensions.DependencyInjection. /// Its platform-specific name avoids ambiguity with that package's GetRequiredService /// extension method. /// public static TService GetRequiredPlatformService(this IServiceProvider provider) where TService : notnull { _ = provider ?? throw new ArgumentNullException(nameof(provider)); object? service = provider.GetService(typeof(TService)); ApplicationStateGuard.Ensure(service is not null, string.Format(CultureInfo.InvariantCulture, PlatformResources.ServiceProviderCannotFindServiceErrorMessage, typeof(TService))); return (TService)service; } /// /// Gets the service of type from the . /// /// The type of the service. /// The service provider. /// The service of type or null if not found. /// Thrown when the is null. public static TService? GetService(this IServiceProvider provider) where TService : class => provider.GetPlatformService(); /// /// Gets the Microsoft Testing Platform service of type /// from the . /// /// The type of the platform service. /// The service provider. /// The platform service of type or null if not found. /// Thrown when the is null. /// /// Prefer this method when the project also references Microsoft.Extensions.DependencyInjection. /// Its platform-specific name avoids ambiguity with that package's GetService extension method. /// public static TService? GetPlatformService(this IServiceProvider provider) where TService : class { _ = provider ?? throw new ArgumentNullException(nameof(provider)); return provider.GetService(typeof(TService)) as TService; } /// /// Gets the message bus from the . /// /// The service provider. /// The message bus. public static IMessageBus GetMessageBus(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredPlatformService(); /// /// Gets the configuration from the . /// /// The service provider. /// The configuration. public static IConfiguration GetConfiguration(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredPlatformService(); /// /// Gets the hierarchical configuration root from the . /// /// The service provider. /// The hierarchical configuration root. public static IConfigurationRoot GetConfigurationRoot(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredPlatformService(); /// /// Gets the artifact naming service from the . /// /// The service provider. /// The artifact naming service. public static IArtifactNamingService GetArtifactNamingService(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredPlatformService(); /// /// Gets the command line options from the . /// /// The service provider. /// The command line options. public static ICommandLineOptions GetCommandLineOptions(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredPlatformService(); /// /// Gets the logger factory from the . /// /// The service provider. /// The logger factory. public static ILoggerFactory GetLoggerFactory(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredPlatformService(); /// /// Gets information about the built-in diagnostic file logger from the . /// /// The service provider. /// /// The diagnostic logging information, or when diagnostic logging is disabled. /// /// /// /// The returned service is live. Extensions created while the test application is still being built /// should retain the service and read when needed, /// because the platform can relocate the log before the build completes. /// /// /// This API is experimental. It may change, break, or be removed at any time without notice. /// /// [Experimental("TPEXP", UrlFormat = "https://aka.ms/testingplatform/diagnostics#{0}")] public static IDiagnosticLoggingInformation? GetDiagnosticLoggingInformation(this IServiceProvider serviceProvider) => serviceProvider.GetPlatformService(); /// /// Gets the output device from the . /// /// The service provider. /// The output device. public static IOutputDevice GetOutputDevice(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); /// /// Gets the IClientInfo from the . /// /// The service provider. /// The IClientInfo object. /// /// This API is experimental. It may change, break, or be removed at any time without notice. /// [Experimental("TPEXP", UrlFormat = "https://aka.ms/testingplatform/diagnostics#{0}")] public static IClientInfo GetClientInfo(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); // Internals extensions internal static TService GetRequiredServiceInternal(this IServiceProvider provider) where TService : notnull { _ = provider ?? throw new ArgumentNullException(nameof(provider)); object? service = ((ServiceProvider)provider).GetServiceInternal(typeof(TService)); ApplicationStateGuard.Ensure(service is not null, string.Format(CultureInfo.InvariantCulture, PlatformResources.ServiceProviderCannotFindServiceErrorMessage, typeof(TService))); return (TService)service; } internal static TService? GetServiceInternal(this IServiceProvider provider) where TService : class { _ = provider ?? throw new ArgumentNullException(nameof(provider)); return ((ServiceProvider)provider).GetServiceInternal(typeof(TService)) as TService; } internal static IEnumerable GetServicesInternal(this IServiceProvider provider) where TService : notnull { _ = provider ?? throw new ArgumentNullException(nameof(provider)); return ((ServiceProvider)provider).GetServicesInternal(typeof(TService)).Cast(); } internal static IReadOnlyList? GetTestHostControllerAuthorizedSecurityIdentities(this IServiceProvider serviceProvider) => ((ServiceProvider)serviceProvider).TestHostControllerAuthorizedSecurityIdentities; internal static async Task?> ResolveTestHostControllerAuthorizedSecurityIdentitiesAsync( this IServiceProvider serviceProvider, ITestHostLauncher? testHostLauncher, string testHostFileName, ILogger logger, CancellationToken cancellationToken) { if (testHostLauncher is not ITestHostControllerConnectionAuthorizer connectionAuthorizer) { ((ServiceProvider)serviceProvider).TestHostControllerAuthorizedSecurityIdentities = null; return null; } IReadOnlyList extensionResult = await connectionAuthorizer.GetAuthorizedSecurityIdentitiesAsync(testHostFileName, cancellationToken).ConfigureAwait(false); if (extensionResult is null || extensionResult.Count == 0) { ((ServiceProvider)serviceProvider).TestHostControllerAuthorizedSecurityIdentities = null; return null; } // Snapshot immediately. Validation, logging, and every controller-side pipe must operate on // the same fixed set of extension-supplied values. string[] securityIdentities = [.. extensionResult]; if (!NamedPipeServerSecurity.IsSupported) { await logger.LogDebugAsync($"'{testHostLauncher.Uid}' requested {securityIdentities.Length} connection authorization(s), ignored on this operating system.").ConfigureAwait(false); ((ServiceProvider)serviceProvider).TestHostControllerAuthorizedSecurityIdentities = null; return null; } foreach (string securityIdentity in securityIdentities.Where(static securityIdentity => !NamedPipeServerSecurity.IsAuthorizableSandboxedApplicationIdentity(securityIdentity))) { throw new InvalidOperationException(string.Format( CultureInfo.InvariantCulture, PlatformResources.TestHostControllerConnectionInvalidAuthorizedSecurityIdentityErrorMessage, testHostLauncher.DisplayName, testHostLauncher.Uid, securityIdentity ?? "", NamedPipeServerSecurity.AllApplicationPackagesSid)); } await logger.LogDebugAsync($"'{testHostLauncher.Uid}' requested the following validated security identity/identities for controller-side connections: {string.Join(", ", securityIdentities)}").ConfigureAwait(false); ((ServiceProvider)serviceProvider).TestHostControllerAuthorizedSecurityIdentities = securityIdentities; return securityIdentities; } internal static ITestSessionContext GetTestSessionContext(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); /// /// Infrastructure. Gets the platform system clock. Not intended for direct use by application code. /// /// The service provider. /// The platform . /// /// This API is experimental. It may change, break, or be removed at any time without notice. /// [EditorBrowsable(EditorBrowsableState.Never)] [Experimental("TPINTERNAL")] public static IClock GetSystemClock(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); internal static ITask GetTask(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); internal static IPlatformOutputDevice GetPlatformOutputDevice(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); internal static IEnvironment GetEnvironment(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); internal static ITestApplicationModuleInfo GetTestApplicationModuleInfo(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); internal static ITestHostControllerInfo GetTestHostControllerInfo(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); internal static IProcessHandler GetProcessHandler(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); internal static IClock GetClock(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); internal static BaseMessageBus GetBaseMessageBus(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); internal static IConsole GetConsole(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); internal static IRuntimeFeature GetRuntimeFeature(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); internal static IAsyncMonitorFactory GetAsyncMonitorFactory(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); internal static ITestApplicationProcessExitCode GetTestApplicationProcessExitCode(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); internal static ITestApplicationCancellationTokenSource GetTestApplicationCancellationTokenSource(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); internal static ITelemetryInformation GetTelemetryInformation(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); internal static ITelemetryCollector GetTelemetryCollector(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); internal static ITestFramework GetTestFramework(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); internal static ITestFrameworkInvoker GetTestFrameworkInvoker(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); internal static IUnhandledExceptionsPolicy GetUnhandledExceptionsPolicy(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); internal static ITestExecutionRequestFactory GetTestExecutionRequestFactory(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); internal static IFileSystem GetFileSystem(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); internal static ITestFrameworkCapabilities GetTestFrameworkCapabilities(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); internal static IPlatformInformation GetPlatformInformation(this IServiceProvider serviceProvider) => serviceProvider.GetRequiredServiceInternal(); internal static IFileLoggerInformation? GetFileLoggerInformation(this IServiceProvider serviceProvider) => serviceProvider.GetServiceInternal(); internal static IPlatformOpenTelemetryService? GetPlatformOTelService(this IServiceProvider serviceProvider) => serviceProvider.GetServiceInternal(); }