// 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();
}