#if NET10_0 extern alias testapphost; #endif using XBullet.EasyTesting.Aspire; using Xunit; namespace TestApi.IntegrationTests; public sealed class AspireTests { [Fact] public void Builder_is_fluent_and_validates_configuration() { var builder = AspireTestHost.Create(); Assert.Same(builder, builder.WithArguments("--environment=Testing")); Assert.Same(builder, builder.ConfigureAppHost(_ => { })); Assert.Same(builder, builder.WaitForResource("api")); Assert.Same(builder, builder.WaitForResource("API")); Assert.Same(builder, builder.WithStartupTimeout(TimeSpan.FromSeconds(30))); Assert.Same(builder, builder.WithMaximumDiagnosticLinesPerResource(25)); Assert.Throws(() => builder.WithStartupTimeout(TimeSpan.Zero)); Assert.Throws(() => builder.WithMaximumDiagnosticLinesPerResource(-1)); Assert.Throws(() => builder.WithArguments(null!)); Assert.Throws(() => builder.WithArguments([null!])); Assert.Throws(() => builder.ConfigureAppHost(null!)); Assert.Throws(() => builder.WaitForResource(" ")); var firstFailure = new InvalidOperationException("first"); var cleanupFailures = AspireTestApplication.AddCleanupFailure( failures: null, firstFailure); Assert.Same( cleanupFailures, AspireTestApplication.AddCleanupFailure( cleanupFailures, new InvalidOperationException("second"))); Assert.Equal(2, cleanupFailures.Count); } [Fact] public void Diagnostics_preserve_resource_state_and_stream_identity() { var log = new AspireResourceLogEntry(42, "service ready", isError: false); var resource = new AspireResourceDiagnostics( "api", "api-1234", "project.v0", "Running", "Healthy", exitCode: null, [log]); var diagnostics = new AspireApplicationDiagnostics( DateTimeOffset.UtcNow, [resource]); Assert.Same(resource, Assert.Single(diagnostics.Resources)); Assert.Same(log, Assert.Single(resource.Logs)); Assert.Equal(42, log.LineNumber); Assert.False(log.IsError); } #if NET10_0 #region docs-aspire-timeout [Fact(Explicit = true)] public async Task Startup_timeout_is_reported_as_timeout_and_cleans_partial_state() { await Assert.ThrowsAsync(() => AspireTestHost.Create() .WithStartupTimeout(TimeSpan.FromMilliseconds(1)) .StartAsync(TestContext.Current.CancellationToken)); } #endregion [Fact(Explicit = true)] public async Task Caller_cancellation_is_preserved_instead_of_reported_as_timeout() { using var cancellation = new CancellationTokenSource(); cancellation.Cancel(); var exception = await Assert.ThrowsAnyAsync(() => AspireTestHost.Create() .StartAsync(cancellation.Token)); Assert.IsNotType(exception); } #region docs-aspire-run-diagnostics [Fact(Explicit = true)] public async Task Distributed_app_waits_for_health_serves_http_and_attaches_failure_diagnostics() { var exception = await Assert.ThrowsAsync(() => AspireTestHost.Create() .WithArguments("--environment=Testing") .ConfigureAppHost(_ => { }) .WaitForResource("api") .WithStartupTimeout(TimeSpan.FromMinutes(2)) .RunAsync( async (application, cancellationToken) => { Assert.Contains("api", application.ResourceNames); Assert.NotNull(application.GetEndpoint("api")); using var client = application.CreateHttpClient("api"); using var response = await client.GetAsync("/health", cancellationToken); response.EnsureSuccessStatusCode(); Assert.Contains( "Healthy", await response.Content.ReadAsStringAsync(cancellationToken)); throw new InvalidOperationException("Expected distributed test failure."); }, TestContext.Current.CancellationToken)); var diagnostics = Assert.IsType( exception.Data[AspireApplicationDiagnostics.ExceptionDataKey]); var api = Assert.Single(diagnostics.Resources, resource => resource.Name == "api"); Assert.Equal("Healthy", api.HealthStatus); Assert.NotEmpty(api.Logs); } #endregion #region docs-aspire-manual-lifecycle [Fact(Explicit = true)] public async Task Distributed_app_exposes_all_resource_operations_and_disposes_idempotently() { var builder = AspireTestHost.Create() .ConfigureAppHost(_ => { }) .WaitForResource("api") .WithMaximumDiagnosticLinesPerResource(1); var application = await builder.StartAsync(TestContext.Current.CancellationToken); Assert.Throws(() => builder.WithArguments("--late")); Assert.Throws(() => builder.ConfigureAppHost(_ => { })); Assert.Throws(() => builder.WaitForResource("api")); Assert.Throws(() => builder.WithStartupTimeout(TimeSpan.FromSeconds(1))); Assert.Throws(() => builder.WithMaximumDiagnosticLinesPerResource(1)); Assert.Contains("api", application.ResourceNames); Assert.NotNull(application.GetEndpoint("api")); Assert.NotNull(application.GetEndpoint("api", "http")); Assert.Throws(() => application.GetEndpoint("api", " ")); await application.WaitForResourceAsync("api", TestContext.Current.CancellationToken); await Assert.ThrowsAsync(async () => await application.GetConnectionStringAsync( "api", TestContext.Current.CancellationToken)); using (var client = application.CreateHttpClient("api")) using (var response = await client.GetAsync("/health", TestContext.Current.CancellationToken)) { response.EnsureSuccessStatusCode(); } using (var client = application.CreateHttpClient("api", "http")) using (var response = await client.GetAsync("/health", TestContext.Current.CancellationToken)) { response.EnsureSuccessStatusCode(); } var diagnostics = await application.CaptureDiagnosticsAsync( TestContext.Current.CancellationToken); Assert.All(diagnostics.Resources, resource => Assert.True(resource.Logs.Count <= 1)); await application.DisposeAsync(); await application.DisposeAsync(); Assert.Throws(() => application.GetEndpoint("api")); } #endregion #endif private sealed class BuilderMarker; }