File: AppHostSmokeTests.cs
Web Access
Project: src\tests\Aspire.Hosting.Tests\Aspire.Hosting.Tests.csproj (Aspire.Hosting.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Globalization;
using Aspire.Hosting.Dcp;
using Microsoft.AspNetCore.InternalTesting;
using Microsoft.DotNet.RemoteExecutor;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
 
//using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;
using Microsoft.Extensions.Options;
 
namespace Aspire.Hosting.Tests;
 
public class AppHostSmokeTests
{
    [Theory]
    [InlineData("invalid-locale", "Invalid locale", null)]
    [InlineData("", null, null)]
    [InlineData("en-US", null, "en-US")]
    [InlineData("fr", null, "fr")]
    [InlineData("fr", null, "fr", "DOTNET_CLI_UI_LANGUAGE")]
    [InlineData("el", "Unsupported locale", null)]
    public void LocaleOverrideReturnsExitCode(string locale, string? expectedLocaleError, string? expectedCulture, string environmentVariableName = "ASPIRE_LOCALE_OVERRIDE")
    {
        var dcpOptions = GetDcpOptions();
 
        // Need to configure DCP details because they're not present in the remote executor assembly.
        var remoteInvokeOptions = new RemoteInvokeOptions();
        remoteInvokeOptions.StartInfo.Environment[$"DcpPublisher__CliPath"] = dcpOptions.CliPath;
        remoteInvokeOptions.StartInfo.Environment[$"DcpPublisher__DashboardPath"] = dcpOptions.DashboardPath;
 
        RemoteExecutor.Invoke(RunTest, locale, expectedLocaleError ?? string.Empty, expectedCulture ?? string.Empty, environmentVariableName, remoteInvokeOptions).Dispose();
 
        static async Task RunTest(string loc, string expectedLocaleError, string expectedCulture, string envVar)
        {
            // Arrange
            var originalCulture = CultureInfo.CurrentCulture;
 
            var testSink = new TestSink();
 
            Environment.SetEnvironmentVariable(envVar, loc);
 
            var builder = DistributedApplication.CreateBuilder(new DistributedApplicationOptions
            {
                DisableDashboard = true
            });
 
            var testService = new TestHostedService();
            builder.Services.AddHostedService(sp => testService);
            builder.Services.AddSingleton<ILoggerProvider>(new TestLoggerProvider(testSink));
 
            var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
            var host = builder.Build();
 
            // Act
            await host.StartAsync().DefaultTimeout();
            await host.StopAsync().DefaultTimeout();
 
            // Assert
            if (!string.IsNullOrEmpty(expectedCulture))
            {
                Assert.NotNull(testService.AppCultureInfo);
                Assert.Equal(expectedCulture, testService.AppCultureInfo.Name);
            }
 
            if (!string.IsNullOrEmpty(expectedLocaleError))
            {
                var writes = testSink.Writes.ToArray();
                var errorLog = testSink.Writes.SingleOrDefault(w => w.Message?.Contains(expectedLocaleError) ?? false);
                Assert.True(
                    errorLog != null,
                    $"""
                    Expected error log not found: {expectedLocaleError}
                    Actual logs: {string.Join(", ", writes.Select(w => w.Message))}
                    """);
            }
 
            // Test culture is reset
            Assert.Equal(originalCulture, CultureInfo.CurrentCulture);
        }
 
        static DcpOptions GetDcpOptions()
        {
            var builder = DistributedApplication.CreateBuilder(new DistributedApplicationOptions
            {
                DisableDashboard = true
            });
            var host = builder.Build();
            var dcpOptions = host.Services.GetRequiredService<IOptions<DcpOptions>>();
            return dcpOptions.Value;
        }
    }
 
    private sealed class TestHostedService : IHostedLifecycleService
    {
        public CultureInfo? AppCultureInfo { get; private set; }
 
        public Task StartAsync(CancellationToken cancellationToken)
        {
            return Task.CompletedTask;
        }
 
        public Task StartedAsync(CancellationToken cancellationToken)
        {
            return Task.CompletedTask;
        }
 
        public Task StartingAsync(CancellationToken cancellationToken)
        {
            AppCultureInfo = CultureInfo.CurrentCulture;
            return Task.CompletedTask;
        }
 
        public Task StopAsync(CancellationToken cancellationToken)
        {
            return Task.CompletedTask;
        }
 
        public Task StoppedAsync(CancellationToken cancellationToken)
        {
            return Task.CompletedTask;
        }
 
        public Task StoppingAsync(CancellationToken cancellationToken)
        {
            return Task.CompletedTask;
        }
    }
}