| File: WaitFailures.cs | Web Access |
| Project: src\playground\Testing\Testing.Tests\Testing.Tests.csproj (Testing.Tests) |
using Xunit; using Aspire.Hosting.Testing; using Aspire.Hosting; using Microsoft.Extensions.Diagnostics.HealthChecks; using Aspire.Hosting.ApplicationModel; namespace Testing.Tests; // These tests cover various scenarios in which a wait operation fails to see how helpful the // resulting errors / logs are public class WaitFailures { private static CancellationTokenSource DefaultCancellationTokenSource() { var cts = CancellationTokenSource.CreateLinkedTokenSource(TestContext.Current.CancellationToken); cts.CancelAfter(TimeSpan.FromMinutes(1)); return cts; } public class WaitForExplicitStartResources { [Fact] public async Task Container() { var cts = DefaultCancellationTokenSource(); await using var builder = DistributedApplicationTestingBuilder.Create(); var nginx = builder.AddContainer("nginx", "nginx", "") .WithExplicitStart(); await using var app = builder.Build(); await app.StartAsync(cts.Token); await app.ResourceNotifications.WaitForResourceAsync(nginx.Resource.Name, cancellationToken: cts.Token); } [Fact] public async Task Executable() { var cts = DefaultCancellationTokenSource(); await using var builder = DistributedApplicationTestingBuilder.Create(); var pwsh = builder.AddExecutable("pwsh", "pwsh", "") .WithExplicitStart(); await using var app = builder.Build(); await app.StartAsync(cts.Token); await app.ResourceNotifications.WaitForResourceAsync(pwsh.Resource.Name, cancellationToken: cts.Token); } } public class WaitForResource { [Fact] public async Task WaitForResourceThatNeverCompletes() { var cts = DefaultCancellationTokenSource(); await using var builder = DistributedApplicationTestingBuilder.Create(); var nginx = builder.AddContainer("nginx", "nginx"); await using var app = builder.Build(); await app.StartAsync(cts.Token); _ = Task.Run(async () => { await app.ResourceNotifications.WaitForResourceAsync(nginx.Resource.Name, cancellationToken: cts.Token); cts.Cancel(); }); await app.ResourceNotifications.WaitForResourceAsync(nginx.Resource.Name, KnownResourceStates.TerminalStates, cancellationToken: cts.Token); } [Fact] public async Task WaitForResourceThatNeverHitsState() { var cts = DefaultCancellationTokenSource(); await using var builder = DistributedApplicationTestingBuilder.Create(); var nginx = builder.AddContainer("nginx", "nginx"); await using var app = builder.Build(); await app.StartAsync(cts.Token); cts.CancelAfter(TimeSpan.FromMilliseconds(100)); await app.ResourceNotifications.WaitForResourceAsync(nginx.Resource.Name, "StateThatIsNeverUsed", cts.Token); } [Fact] public async Task WaitForResourceThatNeverHitsStates() { var cts = DefaultCancellationTokenSource(); await using var builder = DistributedApplicationTestingBuilder.Create(); var nginx = builder.AddContainer("nginx", "nginx"); await using var app = builder.Build(); await app.StartAsync(cts.Token); cts.CancelAfter(TimeSpan.FromMilliseconds(100)); await app.ResourceNotifications.WaitForResourceAsync(nginx.Resource.Name, ["States", "That", "Are", "Never", "Used"], cts.Token); } [Fact] public async Task WaitForResourceThatNeverHitsPredicate() { var cts = DefaultCancellationTokenSource(); await using var builder = DistributedApplicationTestingBuilder.Create(); var nginx = builder.AddContainer("nginx", "nginx"); await using var app = builder.Build(); await app.StartAsync(cts.Token); cts.CancelAfter(TimeSpan.FromMilliseconds(100)); await app.ResourceNotifications.WaitForResourceAsync(nginx.Resource.Name, x => false, cts.Token); } } public class WaitForResourceHealthyAsync { [Fact] public async Task WaitForHealthyOnResourceThatNeverStarts() { var cts = DefaultCancellationTokenSource(); await using var builder = DistributedApplicationTestingBuilder.Create(); var nginx = builder.AddContainer("nginx", "nginx") .WithExplicitStart(); await using var app = builder.Build(); await app.StartAsync(cts.Token); cts.CancelAfter(TimeSpan.FromMilliseconds(100)); await app.ResourceNotifications.WaitForResourceHealthyAsync(nginx.Resource.Name, cts.Token); } [Fact] public async Task WaitForHealthyOnResourceThatStartsButNeverGoesHealthy() { var cts = DefaultCancellationTokenSource(); await using var builder = DistributedApplicationTestingBuilder.Create(); var nginx = builder.AddContainer("nginx", "nginx") .WithHttpEndpoint(targetPort: 80) .WithHttpEndpoint(name: "fake", targetPort: 1234) .WithHttpHealthCheck("/does-not-exist") .WithHttpHealthCheck("/throws-exception", endpointName: "fake"); await using var app = builder.Build(); await app.StartAsync(cts.Token); _ = Task.Run(async () => { await app.ResourceNotifications.WaitForResourceAsync(nginx.Resource.Name, x => x.Snapshot.HealthReports.All(x => x.Status.HasValue), cts.Token); cts.Cancel(); }); await app.ResourceNotifications.WaitForResourceHealthyAsync(nginx.Resource.Name, cts.Token); } [Fact] public async Task WaitForHealthyOnResourceThatGoesHealthyButNeverCompletesResourceReady() { var cts = DefaultCancellationTokenSource(); await using var builder = DistributedApplicationTestingBuilder.Create(); var nginx = builder.AddContainer("nginx", "nginx") .OnResourceReady((_, _, token) => Task.Delay(Timeout.Infinite, token)); await using var app = builder.Build(); await app.StartAsync(cts.Token); _ = Task.Run(async () => { await app.ResourceNotifications.WaitForResourceAsync(nginx.Resource.Name, x => x.Snapshot.HealthStatus == HealthStatus.Healthy, cts.Token); cts.Cancel(); }); await app.ResourceNotifications.WaitForResourceHealthyAsync(nginx.Resource.Name, cts.Token); } } public class WaitForDependencies { [Fact] public async Task DependencyNeverStarts() { var cts = DefaultCancellationTokenSource(); await using var builder = DistributedApplicationTestingBuilder.Create(); var dependency = builder.AddContainer("dependency", "nginx") .WithExplicitStart(); var consumer = builder.AddContainer("consumer", "nginx") .WaitForStart(dependency); await using var app = builder.Build(); // Chicken and egg problem - need `WaitFor` to test `WaitForDependenciesAsync` // but adding `WaitFor` causes `StartAsync` to block until all resource dependencies are started // But I'm trying to test what happens when the waits are not complete. _ = app.StartAsync(cts.Token); cts.CancelAfter(TimeSpan.FromMilliseconds(100)); await app.ResourceNotifications.WaitForDependenciesAsync(consumer.Resource, cts.Token); } [Fact] public async Task DependencyNeverGoesHealthy() { var cts = DefaultCancellationTokenSource(); await using var builder = DistributedApplicationTestingBuilder.Create(); var dependency = builder.AddContainer("dependency", "nginx") .WithHttpEndpoint(targetPort: 80) .WithHttpHealthCheck("/does-not-exist"); var consumer = builder.AddContainer("consumer", "nginx") .WaitFor(dependency); await using var app = builder.Build(); _ = app.StartAsync(cts.Token); _ = Task.Run(async () => { await app.ResourceNotifications.WaitForResourceAsync(dependency.Resource.Name, cancellationToken: cts.Token); cts.Cancel(); }); await app.ResourceNotifications.WaitForDependenciesAsync(consumer.Resource, cts.Token); } [Fact] public async Task DependencyNeverCompletes() { var cts = DefaultCancellationTokenSource(); await using var builder = DistributedApplicationTestingBuilder.Create(); var dependency = builder.AddContainer("dependency", "nginx"); var consumer = builder.AddContainer("consumer", "nginx") .WaitForCompletion(dependency); await using var app = builder.Build(); _ = app.StartAsync(cts.Token); _ = Task.Run(async () => { await app.ResourceNotifications.WaitForResourceAsync(dependency.Resource.Name, cancellationToken: cts.Token); cts.Cancel(); }); await app.ResourceNotifications.WaitForDependenciesAsync(consumer.Resource, cancellationToken: cts.Token); } } }