| File: OperationModesTests.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. #pragma warning disable ASPIREPIPELINES001 #pragma warning disable ASPIREWATCH001 using Aspire.Hosting.Utils; using Microsoft.AspNetCore.InternalTesting; using Microsoft.Extensions.DependencyInjection; namespace Aspire.Hosting.Tests; [Trait("Partition", "2")] public class OperationModesTests(ITestOutputHelper outputHelper) { [Fact] public async Task VerifyBackwardsCompatibleRunModeInvocation() { // The purpose of this test is to verify that the apphost executable will continue // to enter run mode if executed without any arguments. using var builder = TestDistributedApplicationBuilder.Create().WithTestAndResourceLogging(outputHelper); var tcs = new TaskCompletionSource<DistributedApplicationExecutionContext>(); builder.Eventing.Subscribe<AfterResourcesCreatedEvent>((e, ct) => { var context = e.Services.GetRequiredService<DistributedApplicationExecutionContext>(); tcs.SetResult(context); return Task.CompletedTask; }); using var app = builder.Build(); await app.StartAsync().WaitAsync(TestConstants.DefaultTimeoutTimeSpan); var context = await tcs.Task.WaitAsync(TestConstants.DefaultTimeoutTimeSpan); await app.StopAsync().WaitAsync(TestConstants.DefaultTimeoutTimeSpan); Assert.Equal(DistributedApplicationOperation.Run, context.Operation); Assert.True(context.IsRunMode); } [Fact] public async Task VerifyExplicitRunModeInvocation() { // The purpose of this test is to verify that the apphost executable will enter // run mode if executed with the "--operation run" argument. using var builder = TestDistributedApplicationBuilder .Create(["--operation", "run"]) .WithTestAndResourceLogging(outputHelper); var tcs = new TaskCompletionSource<DistributedApplicationExecutionContext>(); builder.Eventing.Subscribe<AfterResourcesCreatedEvent>((e, ct) => { var context = e.Services.GetRequiredService<DistributedApplicationExecutionContext>(); tcs.SetResult(context); return Task.CompletedTask; }); using var app = builder.Build(); await app.StartAsync().WaitAsync(TestConstants.DefaultTimeoutTimeSpan); var context = await tcs.Task.WaitAsync(TestConstants.DefaultTimeoutTimeSpan); await app.StopAsync().WaitAsync(TestConstants.LongTimeoutTimeSpan); Assert.Equal(DistributedApplicationOperation.Run, context.Operation); Assert.True(context.IsRunMode); } [Fact] public async Task VerifyExplicitRunModeWithPublisherInvocation() { // The purpose of this test is to verify that the apphost executable will enter // run mode if executed with the "--operation run" argument. using var builder = TestDistributedApplicationBuilder .Create(["--operation", "run", "--publisher", "manifest"]) .WithTestAndResourceLogging(outputHelper); var tcs = new TaskCompletionSource<DistributedApplicationExecutionContext>(); builder.Eventing.Subscribe<AfterResourcesCreatedEvent>((e, ct) => { var context = e.Services.GetRequiredService<DistributedApplicationExecutionContext>(); tcs.SetResult(context); return Task.CompletedTask; }); using var app = builder.Build(); await app.StartAsync().WaitAsync(TestConstants.DefaultTimeoutTimeSpan); var context = await tcs.Task.WaitAsync(TestConstants.DefaultTimeoutTimeSpan); await app.StopAsync().WaitAsync(TestConstants.DefaultTimeoutTimeSpan); Assert.Equal(DistributedApplicationOperation.Run, context.Operation); Assert.True(context.IsRunMode); } [Fact] public async Task VerifyBackwardsCompatiblePublishModeInvocation() { // The purpose of this test is to verify that the apphost executable will continue // to enter publish mode if the --publisher argument is specified. using var builder = TestDistributedApplicationBuilder .Create(["--publisher", "manifest", "--output-path", "test-output-path"]) .WithTestAndResourceLogging(outputHelper); // TOOD: This won't work because this event does not fire in publish mode. We need // another way to get at this internal state. var tcs = new TaskCompletionSource<DistributedApplicationExecutionContext>(); builder.Eventing.Subscribe<BeforeStartEvent>((e, ct) => { var context = e.Services.GetRequiredService<DistributedApplicationExecutionContext>(); tcs.SetResult(context); return Task.CompletedTask; }); using var app = builder.Build(); await app.StartAsync().WaitAsync(TestConstants.DefaultTimeoutTimeSpan); var context = await tcs.Task.WaitAsync(TestConstants.DefaultTimeoutTimeSpan); await app.StopAsync().WaitAsync(TestConstants.DefaultTimeoutTimeSpan); Assert.Equal(DistributedApplicationOperation.Publish, context.Operation); Assert.True(context.IsPublishMode); } [Fact] public void VerifyExplicitPublishModeInvocation() { // The purpose of this test is to verify that the apphost executable will continue // to enter publish mode if the --publisher argument is specified. using var builder = TestDistributedApplicationBuilder .Create(["--operation", "publish", "--publisher", "manifest", "--output-path", "test-output-path"]) .WithTestAndResourceLogging(outputHelper); Assert.Equal(DistributedApplicationOperation.Publish, builder.ExecutionContext.Operation); } [Fact] public void WatchIsDisabledByDefaultInRunMode() { // Without any watch configuration the AppHost runs without watch. using var builder = TestDistributedApplicationBuilder .Create() .WithTestAndResourceLogging(outputHelper); Assert.True(builder.ExecutionContext.IsRunMode); Assert.False(builder.ExecutionContext.RunConfiguration.WatchEnabled); } [Fact] public void WatchIsEnabledWhenConfigured() { // The "AppHost:Run:WatchEnabled" configuration key enables watch. using var builder = TestDistributedApplicationBuilder .Create(["AppHost:Run:WatchEnabled=true"]) .WithTestAndResourceLogging(outputHelper); Assert.True(builder.ExecutionContext.IsRunMode); Assert.True(builder.ExecutionContext.RunConfiguration.WatchEnabled); } [Fact] public void WatchConfigurationIsCaseInsensitive() { // The value is parsed case-insensitively so callers do not have to match a particular casing. using var builder = TestDistributedApplicationBuilder .Create(["AppHost:Run:WatchEnabled=TRUE"]) .WithTestAndResourceLogging(outputHelper); Assert.True(builder.ExecutionContext.RunConfiguration.WatchEnabled); } [Fact] public void WatchIsDisabledForUnparseableValue() { // An unrecognized value must never fail the run; watch stays disabled. using var builder = TestDistributedApplicationBuilder .Create(["AppHost:Run:WatchEnabled=bogus"]) .WithTestAndResourceLogging(outputHelper); Assert.True(builder.ExecutionContext.IsRunMode); Assert.False(builder.ExecutionContext.RunConfiguration.WatchEnabled); } [Fact] public void WatchIsDisabledForNumericValue() { // Some configuration sources emit "1" for booleans. bool.TryParse rejects it, so watch stays // disabled rather than being silently enabled by a value the AppHost does not accept. using var builder = TestDistributedApplicationBuilder .Create(["AppHost:Run:WatchEnabled=1"]) .WithTestAndResourceLogging(outputHelper); Assert.True(builder.ExecutionContext.IsRunMode); Assert.False(builder.ExecutionContext.RunConfiguration.WatchEnabled); } [Fact] public void WatchIsDisabledInPublishModeEvenWhenConfigured() { // The run configuration is only meaningful in run mode; publish mode always reports defaults. using var builder = TestDistributedApplicationBuilder .Create(["--operation", "publish", "--publisher", "manifest", "--output-path", "test-output-path", "AppHost:Run:WatchEnabled=true"]) .WithTestAndResourceLogging(outputHelper); Assert.True(builder.ExecutionContext.IsPublishMode); Assert.False(builder.ExecutionContext.RunConfiguration.WatchEnabled); } [Fact] public void RunConfigurationIsDefaultWhenExecutionContextConstructedForPublish() { // The run configuration only applies to run mode. Even if a caller constructs options with watch // enabled and a Publish operation, the execution context must report defaults (publish never watches). var options = new DistributedApplicationExecutionContextOptions(DistributedApplicationOperation.Publish) { RunConfiguration = new RunConfiguration { WatchEnabled = true } }; var context = new DistributedApplicationExecutionContext(options); Assert.True(context.IsPublishMode); Assert.False(context.RunConfiguration.WatchEnabled); } [Fact] public void RunConfigurationIsNeverNull() { // Every constructor must produce a usable run configuration so integrations never have to null-check it. Assert.NotNull(new DistributedApplicationExecutionContext(DistributedApplicationOperation.Run).RunConfiguration); Assert.NotNull(new DistributedApplicationExecutionContext(DistributedApplicationOperation.Publish, "manifest").RunConfiguration); Assert.NotNull(new DistributedApplicationExecutionContext(new DistributedApplicationExecutionContextOptions(DistributedApplicationOperation.Run)).RunConfiguration); } }