diff --git a/tests/Aspire.Components.Common.Tests/TestConstants.cs b/tests/Aspire.Components.Common.Tests/ComponentTestConstants.cs similarity index 86% rename from tests/Aspire.Components.Common.Tests/TestConstants.cs rename to tests/Aspire.Components.Common.Tests/ComponentTestConstants.cs index 4b7971bf1f7..f31dcce7d79 100644 --- a/tests/Aspire.Components.Common.Tests/TestConstants.cs +++ b/tests/Aspire.Components.Common.Tests/ComponentTestConstants.cs @@ -3,7 +3,7 @@ namespace Aspire.Components.Common.Tests; -public static class TestConstants +public static class ComponentTestConstants { public const string AspireTestContainerRegistry = "netaspireci.azurecr.io"; } diff --git a/tests/Aspire.Elastic.Clients.Elasticsearch.Tests/ElasticsearchContainerFixture.cs b/tests/Aspire.Elastic.Clients.Elasticsearch.Tests/ElasticsearchContainerFixture.cs index 037cca297c7..881ba94431d 100644 --- a/tests/Aspire.Elastic.Clients.Elasticsearch.Tests/ElasticsearchContainerFixture.cs +++ b/tests/Aspire.Elastic.Clients.Elasticsearch.Tests/ElasticsearchContainerFixture.cs @@ -20,7 +20,7 @@ public async Task InitializeAsync() if (RequiresDockerAttribute.IsSupported) { Container = new ElasticsearchBuilder() - .WithImage($"{TestConstants.AspireTestContainerRegistry}/{ElasticsearchContainerImageTags.Image}:{ElasticsearchContainerImageTags.Tag}") + .WithImage($"{ComponentTestConstants.AspireTestContainerRegistry}/{ElasticsearchContainerImageTags.Image}:{ElasticsearchContainerImageTags.Tag}") .Build(); await Container.StartAsync(); } diff --git a/tests/Aspire.Hosting.Redis.Tests/RedisFunctionalTests.cs b/tests/Aspire.Hosting.Redis.Tests/RedisFunctionalTests.cs index ff6e91d44cc..0b01d424031 100644 --- a/tests/Aspire.Hosting.Redis.Tests/RedisFunctionalTests.cs +++ b/tests/Aspire.Hosting.Redis.Tests/RedisFunctionalTests.cs @@ -130,7 +130,7 @@ public async Task VerifyDatabasesAreNotDuplicatedForPersistentRedisInsightContai var configure = (DistributedApplicationOptions options) => { - options.ContainerRegistryOverride = TestConstants.AspireTestContainerRegistry; + options.ContainerRegistryOverride = ComponentTestConstants.AspireTestContainerRegistry; }; using var builder1 = TestDistributedApplicationBuilder.Create(configure, testOutputHelper); diff --git a/tests/Aspire.Hosting.Tests/AddParameterTests.cs b/tests/Aspire.Hosting.Tests/AddParameterTests.cs index 763dad147bf..128858627d4 100644 --- a/tests/Aspire.Hosting.Tests/AddParameterTests.cs +++ b/tests/Aspire.Hosting.Tests/AddParameterTests.cs @@ -4,6 +4,7 @@ using Aspire.Hosting.Lifecycle; using Aspire.Hosting.Publishing; using Aspire.Hosting.Utils; +using Microsoft.AspNetCore.InternalTesting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Xunit; @@ -147,7 +148,7 @@ public async Task ParametersWithDefaultValueStringOverloadUsedRegardlessOfConfig Assert.Equal($"DefaultValue", parameterResource.Value); // The manifest should not include anything about the default value - var paramManifest = await ManifestUtils.GetManifest(appModel.Resources.OfType().Single(r => r.Name == "pass")); + var paramManifest = await ManifestUtils.GetManifest(appModel.Resources.OfType().Single(r => r.Name == "pass")).DefaultTimeout(); var expectedManifest = $$""" { "type": "parameter.v0", @@ -197,7 +198,7 @@ public async Task ParametersWithDefaultValueGetPublishedIfPublishFlagIsPassed(bo Assert.Equal($"DefaultValue", parameterResource.Value); // The manifest should include the default value, since we passed publishValueAsDefault: true - var paramManifest = await ManifestUtils.GetManifest(appModel.Resources.OfType().Single(r => r.Name == "pass")); + var paramManifest = await ManifestUtils.GetManifest(appModel.Resources.OfType().Single(r => r.Name == "pass")).DefaultTimeout(); var expectedManifest = $$""" { "type": "parameter.v0", @@ -255,7 +256,7 @@ public async Task ParametersWithDefaultValueObjectOverloadUsedRegardlessOfConfig Assert.Equal(10, parameterResource.Value.Length); // The manifest should include the fields for the generated default value - var paramManifest = await ManifestUtils.GetManifest(appModel.Resources.OfType().Single(r => r.Name == "pass")); + var paramManifest = await ManifestUtils.GetManifest(appModel.Resources.OfType().Single(r => r.Name == "pass")).DefaultTimeout(); var expectedManifest = $$""" { "type": "parameter.v0", @@ -310,7 +311,7 @@ public async Task ParametersCanGetValueFromNonDefaultConfigurationKeys() Assert.Equal($"MyAccessToken", parameterResource.Value); // The manifest is not affected by the custom configuration key - var paramManifest = await ManifestUtils.GetManifest(appModel.Resources.OfType().Single(r => r.Name == "val")); + var paramManifest = await ManifestUtils.GetManifest(appModel.Resources.OfType().Single(r => r.Name == "val")).DefaultTimeout(); var expectedManifest = $$""" { "type": "parameter.v0", diff --git a/tests/Aspire.Hosting.Tests/Aspire.Hosting.Tests.csproj b/tests/Aspire.Hosting.Tests/Aspire.Hosting.Tests.csproj index 4abc103be50..484d9f39408 100644 --- a/tests/Aspire.Hosting.Tests/Aspire.Hosting.Tests.csproj +++ b/tests/Aspire.Hosting.Tests/Aspire.Hosting.Tests.csproj @@ -23,7 +23,6 @@ - diff --git a/tests/Aspire.Hosting.Tests/Dashboard/DashboardLifecycleHookTests.cs b/tests/Aspire.Hosting.Tests/Dashboard/DashboardLifecycleHookTests.cs index 0cd7644049c..b66eedde69f 100644 --- a/tests/Aspire.Hosting.Tests/Dashboard/DashboardLifecycleHookTests.cs +++ b/tests/Aspire.Hosting.Tests/Dashboard/DashboardLifecycleHookTests.cs @@ -8,6 +8,7 @@ using Aspire.Hosting.Dashboard; using Aspire.Hosting.Dcp; using Aspire.Hosting.Tests.Utils; +using Microsoft.AspNetCore.InternalTesting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; @@ -42,12 +43,12 @@ public async Task WatchDashboardLogs_WrittenToHostLoggerFactory(DateTime? timest var hook = CreateHook(resourceLoggerService, resourceNotificationService, configuration, loggerFactory: factory); var model = new DistributedApplicationModel(new ResourceCollection()); - await hook.BeforeStartAsync(model, CancellationToken.None); + await hook.BeforeStartAsync(model, CancellationToken.None).DefaultTimeout(); - await resourceNotificationService.PublishUpdateAsync(model.Resources.Single(), s => s); + await resourceNotificationService.PublishUpdateAsync(model.Resources.Single(), s => s).DefaultTimeout(); string resourceId = default!; - await foreach (var item in resourceLoggerService.WatchAnySubscribersAsync()) + await foreach (var item in resourceLoggerService.WatchAnySubscribersAsync().DefaultTimeout()) { if (item.Name.StartsWith(KnownResourceNames.AspireDashboard) && item.AnySubscribers) { @@ -61,10 +62,9 @@ public async Task WatchDashboardLogs_WrittenToHostLoggerFactory(DateTime? timest dashboardLoggerState.AddLog(LogEntry.Create(timestamp, logMessage, isErrorMessage: false), inMemorySource: true); // Assert - var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); - while (!cts.IsCancellationRequested) + while (true) { - var logContext = await logChannel.Reader.ReadAsync(cts.Token); + var logContext = await logChannel.Reader.ReadAsync().DefaultTimeout(); if (logContext.LoggerName == expectedCategory) { Assert.Equal(expectedMessage, logContext.Message); @@ -86,7 +86,7 @@ public async Task BeforeStartAsync_ExcludeLifecycleCommands_CommandsNotAddedToDa var model = new DistributedApplicationModel(new ResourceCollection()); // Act - await hook.BeforeStartAsync(model, CancellationToken.None); + await hook.BeforeStartAsync(model, CancellationToken.None).DefaultTimeout(); var dashboardResource = model.Resources.Single(r => string.Equals(r.Name, KnownResourceNames.AspireDashboard, StringComparisons.ResourceName)); dashboardResource.AddLifeCycleCommands(); diff --git a/tests/Aspire.Hosting.Tests/Dashboard/DashboardResourceTests.cs b/tests/Aspire.Hosting.Tests/Dashboard/DashboardResourceTests.cs index 7fa6c37ad36..05c9962306b 100644 --- a/tests/Aspire.Hosting.Tests/Dashboard/DashboardResourceTests.cs +++ b/tests/Aspire.Hosting.Tests/Dashboard/DashboardResourceTests.cs @@ -7,6 +7,7 @@ using Aspire.Hosting.Dcp; using Aspire.Hosting.Tests.Utils; using Aspire.Hosting.Utils; +using Microsoft.AspNetCore.InternalTesting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -40,7 +41,7 @@ public async Task DashboardIsAutomaticallyAddedAsHiddenResource() using var app = builder.Build(); - await app.ExecuteBeforeStartHooksAsync(default); + await app.ExecuteBeforeStartHooksAsync(default).DefaultTimeout(); var model = app.Services.GetRequiredService(); @@ -64,7 +65,7 @@ public async Task DashboardIsAddedFirst() using var app = builder.Build(); - await app.ExecuteBeforeStartHooksAsync(default); + await app.ExecuteBeforeStartHooksAsync(default).DefaultTimeout(); var model = app.Services.GetRequiredService(); @@ -95,7 +96,7 @@ public async Task DashboardDoesNotAddResource_ConfiguresExistingDashboard() using var app = builder.Build(); - await app.ExecuteBeforeStartHooksAsync(default); + await app.ExecuteBeforeStartHooksAsync(default).DefaultTimeout(); var model = app.Services.GetRequiredService(); @@ -103,7 +104,7 @@ public async Task DashboardDoesNotAddResource_ConfiguresExistingDashboard() Assert.Same(container.Resource, dashboard); - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(dashboard, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(dashboard, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); Assert.Collection(config, e => @@ -165,13 +166,13 @@ public async Task DashboardWithDllPathLaunchesDotnet() var app = builder.Build(); - await app.ExecuteBeforeStartHooksAsync(default); + await app.ExecuteBeforeStartHooksAsync(default).DefaultTimeout(); var model = app.Services.GetRequiredService(); var dashboard = Assert.Single(model.Resources.OfType()); - var args = await ArgumentEvaluator.GetArgumentListAsync(dashboard); + var args = await ArgumentEvaluator.GetArgumentListAsync(dashboard).DefaultTimeout(); Assert.NotNull(dashboard); Assert.Equal("aspire-dashboard", dashboard.Name); @@ -201,13 +202,13 @@ public async Task DashboardAuthConfigured_EnvVarsPresent() using var app = builder.Build(); - await app.ExecuteBeforeStartHooksAsync(default); + await app.ExecuteBeforeStartHooksAsync(default).DefaultTimeout(); var model = app.Services.GetRequiredService(); var dashboard = Assert.Single(model.Resources); - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(dashboard, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(dashboard, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); Assert.Equal("BrowserToken", config.Single(e => e.Key == DashboardConfigNames.DashboardFrontendAuthModeName.EnvVarName).Value); Assert.Equal("TestBrowserToken!", config.Single(e => e.Key == DashboardConfigNames.DashboardFrontendBrowserTokenName.EnvVarName).Value); @@ -236,13 +237,13 @@ public async Task DashboardAuthRemoved_EnvVarsUnsecured() using var app = builder.Build(); - await app.ExecuteBeforeStartHooksAsync(default); + await app.ExecuteBeforeStartHooksAsync(default).DefaultTimeout(); var model = app.Services.GetRequiredService(); var dashboard = Assert.Single(model.Resources); - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(dashboard, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(dashboard, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); Assert.Equal("Unsecured", config.Single(e => e.Key == DashboardConfigNames.DashboardFrontendAuthModeName.EnvVarName).Value); Assert.Equal("Unsecured", config.Single(e => e.Key == DashboardConfigNames.DashboardOtlpAuthModeName.EnvVarName).Value); @@ -268,13 +269,13 @@ public async Task DashboardResourceServiceUriIsSet() using var app = builder.Build(); - await app.ExecuteBeforeStartHooksAsync(default); + await app.ExecuteBeforeStartHooksAsync(default).DefaultTimeout(); var model = app.Services.GetRequiredService(); var dashboard = Assert.Single(model.Resources); - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(dashboard, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(dashboard, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); Assert.Equal("http://localhost:5000", config.Single(e => e.Key == DashboardConfigNames.ResourceServiceUrlName.EnvVarName).Value); } @@ -301,7 +302,7 @@ public async Task DashboardResource_OtlpHttpEndpoint_CorsEnvVarSet() using var app = builder.Build(); - await app.ExecuteBeforeStartHooksAsync(default); + await app.ExecuteBeforeStartHooksAsync(default).DefaultTimeout(); var model = app.Services.GetRequiredService(); @@ -312,7 +313,7 @@ public async Task DashboardResource_OtlpHttpEndpoint_CorsEnvVarSet() var dashboard = Assert.Single(model.Resources.Where(r => r.Name == "aspire-dashboard")); - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(dashboard, DistributedApplicationOperation.Run, app.Services); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(dashboard, DistributedApplicationOperation.Run, app.Services).DefaultTimeout(); Assert.Equal("http://localhost:8081,http://localhost:58080", config.Single(e => e.Key == DashboardConfigNames.DashboardOtlpCorsAllowedOriginsKeyName.EnvVarName).Value); Assert.Equal("*", config.Single(e => e.Key == DashboardConfigNames.DashboardOtlpCorsAllowedHeadersKeyName.EnvVarName).Value); @@ -340,13 +341,13 @@ public async Task DashboardResource_OtlpGrpcEndpoint_CorsEnvVarNotSet() using var app = builder.Build(); - await app.ExecuteBeforeStartHooksAsync(default); + await app.ExecuteBeforeStartHooksAsync(default).DefaultTimeout(); var model = app.Services.GetRequiredService(); var dashboard = Assert.Single(model.Resources.Where(r => r.Name == "aspire-dashboard")); - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(dashboard, DistributedApplicationOperation.Run, app.Services); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(dashboard, DistributedApplicationOperation.Run, app.Services).DefaultTimeout(); Assert.DoesNotContain(config, e => e.Key == DashboardConfigNames.DashboardOtlpCorsAllowedOriginsKeyName.EnvVarName); Assert.DoesNotContain(config, e => e.Key == DashboardConfigNames.DashboardOtlpCorsAllowedHeadersKeyName.EnvVarName); @@ -365,7 +366,7 @@ public async Task DashboardIsNotAddedInPublishMode() using var app = builder.Build(); - await app.ExecuteBeforeStartHooksAsync(default); + await app.ExecuteBeforeStartHooksAsync(default).DefaultTimeout(); var model = app.Services.GetRequiredService(); @@ -381,7 +382,7 @@ public async Task DashboardIsNotAddedIfDisabled() var app = builder.Build(); - await app.ExecuteBeforeStartHooksAsync(default); + await app.ExecuteBeforeStartHooksAsync(default).DefaultTimeout(); var model = app.Services.GetRequiredService(); @@ -446,7 +447,7 @@ public async Task DashboardLifecycleHookWatchesLogs(LogLevel logLevel) } }); - await app.ExecuteBeforeStartHooksAsync(default).WaitAsync(TimeSpan.FromSeconds(15)); + await app.ExecuteBeforeStartHooksAsync(default).DefaultTimeout(); var model = app.Services.GetRequiredService(); var resourceNotificationService = app.Services.GetRequiredService(); @@ -457,10 +458,10 @@ public async Task DashboardLifecycleHookWatchesLogs(LogLevel logLevel) Assert.Equal("aspire-dashboard", dashboard.Name); // Push a notification through to the dashboard resource. - await resourceNotificationService.PublishUpdateAsync(dashboard, "aspire-dashboard-0", s => s with { State = "Running" }); + await resourceNotificationService.PublishUpdateAsync(dashboard, "aspire-dashboard-0", s => s with { State = "Running" }).DefaultTimeout(); // Wait for logs to be subscribed to - await watchForLogSubs.WaitAsync(TimeSpan.FromSeconds(15)); + await watchForLogSubs.DefaultTimeout(); // Push some logs through to the dashboard resource. var logger = resourceLoggerService.GetLogger("aspire-dashboard-0"); @@ -481,12 +482,12 @@ public async Task DashboardLifecycleHookWatchesLogs(LogLevel logLevel) Assert.NotNull(testLogger); // Get the first log message that was logged - var log = await testLogger.FirstLogTask.WaitAsync(TimeSpan.FromSeconds(15)); + var log = await testLogger.FirstLogTask.DefaultTimeout(); Assert.Equal("Test dashboard message", log.Message); Assert.Equal(logLevel, log.LogLevel); - await app.DisposeAsync().AsTask().WaitAsync(TimeSpan.FromSeconds(15)); + await app.DisposeAsync().AsTask().DefaultTimeout(); } [Fact] @@ -498,7 +499,7 @@ public async Task DashboardIsExcludedFromManifestInPublishModeEvenIfAddedExplici var app = builder.Build(); - await app.ExecuteBeforeStartHooksAsync(default); + await app.ExecuteBeforeStartHooksAsync(default).DefaultTimeout(); var model = app.Services.GetRequiredService(); @@ -507,7 +508,7 @@ public async Task DashboardIsExcludedFromManifestInPublishModeEvenIfAddedExplici Assert.NotNull(dashboard); var annotation = Assert.Single(dashboard.Annotations.OfType()); - var manifest = await ManifestUtils.GetManifestOrNull(dashboard); + var manifest = await ManifestUtils.GetManifestOrNull(dashboard).DefaultTimeout(); Assert.Equal("aspire-dashboard", dashboard.Name); Assert.Same(ManifestPublishingCallbackAnnotation.Ignore, annotation); diff --git a/tests/Aspire.Hosting.Tests/Dashboard/ResourcePublisherTests.cs b/tests/Aspire.Hosting.Tests/Dashboard/ResourcePublisherTests.cs index 9f4fb0e48b3..bc39540e67c 100644 --- a/tests/Aspire.Hosting.Tests/Dashboard/ResourcePublisherTests.cs +++ b/tests/Aspire.Hosting.Tests/Dashboard/ResourcePublisherTests.cs @@ -3,6 +3,7 @@ using Aspire.Dashboard.Model; using Aspire.Hosting.Dashboard; +using Microsoft.AspNetCore.InternalTesting; using Xunit; namespace Aspire.Hosting.Tests.Dashboard; @@ -19,8 +20,8 @@ public async Task ProducesExpectedSnapshotAndUpdates() var b = CreateResourceSnapshot("B"); var c = CreateResourceSnapshot("C"); - await publisher.IntegrateAsync(new TestResource("A"), a, ResourceSnapshotChangeType.Upsert); - await publisher.IntegrateAsync(new TestResource("B"), b, ResourceSnapshotChangeType.Upsert); + await publisher.IntegrateAsync(new TestResource("A"), a, ResourceSnapshotChangeType.Upsert).DefaultTimeout(); + await publisher.IntegrateAsync(new TestResource("B"), b, ResourceSnapshotChangeType.Upsert).DefaultTimeout(); Assert.Equal(0, publisher.OutgoingSubscriberCount); @@ -42,17 +43,17 @@ public async Task ProducesExpectedSnapshotAndUpdates() } }); - await publisher.IntegrateAsync(new TestResource("C"), c, ResourceSnapshotChangeType.Upsert); + await publisher.IntegrateAsync(new TestResource("C"), c, ResourceSnapshotChangeType.Upsert).DefaultTimeout(); - var change = Assert.Single(await tcs.Task); + var change = Assert.Single(await tcs.Task.DefaultTimeout()); Assert.Equal(ResourceSnapshotChangeType.Upsert, change.ChangeType); Assert.Equal("C", change.Resource.Name); - await cts.CancelAsync(); + await cts.CancelAsync().DefaultTimeout(); try { - await task; + await task.DefaultTimeout(); } catch (OperationCanceledException) { @@ -72,8 +73,8 @@ public async Task SupportsMultipleSubscribers() var b = CreateResourceSnapshot("B"); var c = CreateResourceSnapshot("C"); - await publisher.IntegrateAsync(new TestResource("A"), a, ResourceSnapshotChangeType.Upsert); - await publisher.IntegrateAsync(new TestResource("B"), b, ResourceSnapshotChangeType.Upsert); + await publisher.IntegrateAsync(new TestResource("A"), a, ResourceSnapshotChangeType.Upsert).DefaultTimeout(); + await publisher.IntegrateAsync(new TestResource("B"), b, ResourceSnapshotChangeType.Upsert).DefaultTimeout(); Assert.Equal(0, publisher.OutgoingSubscriberCount); @@ -85,13 +86,13 @@ public async Task SupportsMultipleSubscribers() Assert.Equal(2, snapshot1.Length); Assert.Equal(2, snapshot2.Length); - await publisher.IntegrateAsync(new TestResource("C"), c, ResourceSnapshotChangeType.Upsert); + await publisher.IntegrateAsync(new TestResource("C"), c, ResourceSnapshotChangeType.Upsert).DefaultTimeout(); var enumerator1 = subscription1.GetAsyncEnumerator(cts.Token); var enumerator2 = subscription2.GetAsyncEnumerator(cts.Token); - await enumerator1.MoveNextAsync(); - await enumerator2.MoveNextAsync(); + await enumerator1.MoveNextAsync().DefaultTimeout(); + await enumerator2.MoveNextAsync().DefaultTimeout(); var v1 = Assert.Single(enumerator1.Current); var v2 = Assert.Single(enumerator2.Current); @@ -101,10 +102,10 @@ public async Task SupportsMultipleSubscribers() Assert.Equal("C", v1.Resource.Name); Assert.Equal("C", v2.Resource.Name); - await cts.CancelAsync(); + await cts.CancelAsync().DefaultTimeout(); - Assert.False(await enumerator1.MoveNextAsync()); - Assert.False(await enumerator2.MoveNextAsync()); + Assert.False(await enumerator1.MoveNextAsync().DefaultTimeout()); + Assert.False(await enumerator2.MoveNextAsync().DefaultTimeout()); Assert.Equal(0, publisher.OutgoingSubscriberCount); } @@ -119,15 +120,15 @@ public async Task MergesResourcesInSnapshot() var a2 = CreateResourceSnapshot("A"); var a3 = CreateResourceSnapshot("A"); - await publisher.IntegrateAsync(new TestResource("A"), a1, ResourceSnapshotChangeType.Upsert); - await publisher.IntegrateAsync(new TestResource("A"), a2, ResourceSnapshotChangeType.Upsert); - await publisher.IntegrateAsync(new TestResource("A"), a3, ResourceSnapshotChangeType.Upsert); + await publisher.IntegrateAsync(new TestResource("A"), a1, ResourceSnapshotChangeType.Upsert).DefaultTimeout(); + await publisher.IntegrateAsync(new TestResource("A"), a2, ResourceSnapshotChangeType.Upsert).DefaultTimeout(); + await publisher.IntegrateAsync(new TestResource("A"), a3, ResourceSnapshotChangeType.Upsert).DefaultTimeout(); var (snapshot, _) = publisher.Subscribe(); Assert.Equal("A", Assert.Single(snapshot).Name); - await cts.CancelAsync(); + await cts.CancelAsync().DefaultTimeout(); } [Fact] @@ -139,15 +140,15 @@ public async Task DeletesRemoveFromSnapshot() var a = CreateResourceSnapshot("A"); var b = CreateResourceSnapshot("B"); - await publisher.IntegrateAsync(new TestResource("A"), a, ResourceSnapshotChangeType.Upsert); - await publisher.IntegrateAsync(new TestResource("B"), b, ResourceSnapshotChangeType.Upsert); - await publisher.IntegrateAsync(new TestResource("A"), a, ResourceSnapshotChangeType.Delete); + await publisher.IntegrateAsync(new TestResource("A"), a, ResourceSnapshotChangeType.Upsert).DefaultTimeout(); + await publisher.IntegrateAsync(new TestResource("B"), b, ResourceSnapshotChangeType.Upsert).DefaultTimeout(); + await publisher.IntegrateAsync(new TestResource("A"), a, ResourceSnapshotChangeType.Delete).DefaultTimeout(); var (snapshot, _) = publisher.Subscribe(); Assert.Equal("B", Assert.Single(snapshot).Name); - await cts.CancelAsync(); + await cts.CancelAsync().DefaultTimeout(); } [Fact] @@ -168,15 +169,15 @@ public async Task CancelledSubscriptionIsCleanedUp() called = true; // Now we've received something, cancel. - await cts.CancelAsync(); + await cts.CancelAsync().DefaultTimeout(); } }); // Push through an update. - await publisher.IntegrateAsync(new TestResource("A"), CreateResourceSnapshot("A"), ResourceSnapshotChangeType.Upsert); + await publisher.IntegrateAsync(new TestResource("A"), CreateResourceSnapshot("A"), ResourceSnapshotChangeType.Upsert).DefaultTimeout(); // Let the subscriber exit. - await task; + await task.DefaultTimeout(); } private static GenericResourceSnapshot CreateResourceSnapshot(string name) diff --git a/tests/Aspire.Hosting.Tests/Dcp/ApplicationExecutorTests.cs b/tests/Aspire.Hosting.Tests/Dcp/ApplicationExecutorTests.cs index 165901aee10..f47767da08a 100644 --- a/tests/Aspire.Hosting.Tests/Dcp/ApplicationExecutorTests.cs +++ b/tests/Aspire.Hosting.Tests/Dcp/ApplicationExecutorTests.cs @@ -560,7 +560,6 @@ public async Task ResourceLogging_ReplayBacklog_SentInBatch() var exeResource = Assert.Single(kubernetesService.CreatedResources.OfType()); // Start watching logs for container. - var watchCts = new CancellationTokenSource(); var watchSubscribers = resourceLoggerService.WatchAnySubscribersAsync(); var watchSubscribersEnumerator = watchSubscribers.GetAsyncEnumerator(); var watchLogs1 = resourceLoggerService.WatchAsync(exeResource.Metadata.Name); diff --git a/tests/Aspire.Hosting.Tests/DistributedApplicationTests.cs b/tests/Aspire.Hosting.Tests/DistributedApplicationTests.cs index 1fdf99710de..3621eb5a100 100644 --- a/tests/Aspire.Hosting.Tests/DistributedApplicationTests.cs +++ b/tests/Aspire.Hosting.Tests/DistributedApplicationTests.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics; using System.Globalization; using System.Text.RegularExpressions; using Aspire.Components.Common.Tests; @@ -14,6 +13,7 @@ using Aspire.Hosting.Tests.Utils; using Aspire.Hosting.Utils; using k8s.Models; +using Microsoft.AspNetCore.InternalTesting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; @@ -21,6 +21,7 @@ using Xunit; using Xunit.Abstractions; using Xunit.Sdk; +using TestConstants = Microsoft.AspNetCore.InternalTesting.TestConstants; namespace Aspire.Hosting.Tests; @@ -56,7 +57,7 @@ public async Task RegisteredLifecycleHookIsExecutedWhenRunAsynchronously() var cts = new CancellationTokenSource(); cts.CancelAfter(TimeSpan.FromMinutes(1)); await testProgram.RunAsync(cts.Token); - }); + }).DefaultTimeout(); Assert.Equal(exceptionMessage, ex.Message); } @@ -97,7 +98,7 @@ public async Task MultipleRegisteredLifecycleHooksAreExecuted() var cts = new CancellationTokenSource(); cts.CancelAfter(TimeSpan.FromMinutes(1)); await testProgram.RunAsync(cts.Token); - }); + }).DefaultTimeout(); Assert.Equal(exceptionMessage, ex.Message); Assert.True(signal.FirstHookExecuted); @@ -152,9 +153,9 @@ public async Task AllocatedPortsAssignedAfterHookRuns() await using var app = testProgram.Build(); - await app.StartAsync(); + await app.StartAsync().DefaultTimeout(); - var appModel = await tcs.Task.WaitAsync(TimeSpan.FromSeconds(10)); + var appModel = await tcs.Task.DefaultTimeout(); foreach (var item in appModel.Resources) { @@ -190,51 +191,45 @@ public async Task TestServicesWithMultipleReplicas() var logger = app.Services.GetRequiredService>(); - using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1)); - - await app.StartAsync(cts.Token); + await app.StartAsync().DefaultTimeout(); - // Make sure services A and C are running + logger.LogInformation("Make sure services A and C are running"); using var clientA = app.CreateHttpClient(testProgram.ServiceABuilder.Resource.Name, "http"); - await clientA.GetStringAsync("/pid", cts.Token); - using var clientC = app.CreateHttpClient(testProgram.ServiceCBuilder.Resource.Name, "http"); - await clientC.GetStringAsync("/pid", cts.Token); + + await Task.WhenAll(clientA.GetStringAsync("/pid"), clientC.GetStringAsync("/pid")).DefaultTimeout(TestConstants.LongTimeoutDuration); // We should get 3 distinct PIDs from service B Dictionary pids = []; - try + var uri = app.GetEndpoint(testProgram.ServiceBBuilder.Resource.Name, "http"); + + var cts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(); + while (!cts.IsCancellationRequested) { - var uri = app.GetEndpoint(testProgram.ServiceBBuilder.Resource.Name, "http"); - while (true) + using var clientB = new HttpClient(); + var url = $"{uri}pid"; + logger.LogInformation("Calling PID API at {Url}", url); + var pidText = await clientB.GetStringAsync(url).DefaultTimeout(); + if (!string.IsNullOrEmpty(pidText)) { - using var clientB = new HttpClient(); - var url = $"{uri}pid"; - logger.LogInformation("Calling PID API at {Url}", url); - var pidText = await clientB.GetStringAsync(url, cts.Token); - if (!string.IsNullOrEmpty(pidText)) + var pid = int.Parse(pidText, CultureInfo.InvariantCulture); + if (pids.TryAdd(pid, true)) { - var pid = int.Parse(pidText, CultureInfo.InvariantCulture); - if (pids.TryAdd(pid, true)) - { - logger.LogInformation("PID API returned new value: {PID}", pid); + logger.LogInformation("PID API returned new value: {PID}", pid); - if (pids.Count == replicaCount) - { - logger.LogInformation("Success! We heard from all {ReplicaCount} replicas.", replicaCount); - break; - } + if (pids.Count == replicaCount) + { + logger.LogInformation("Success! We heard from all {ReplicaCount} replicas.", replicaCount); + break; } } - - await Task.Delay(100, cts.Token); } + + await Task.Delay(100); } - catch (OperationCanceledException) - { - Assert.Equal(3, pids.Count); - } + + Assert.Equal(3, pids.Count); } [Fact] @@ -251,10 +246,10 @@ public async Task VerifyDockerAppWorks() await using var app = testProgram.Build(); - await app.StartAsync(); + await app.StartAsync().DefaultTimeout(); var s = app.Services.GetRequiredService(); - var list = await s.ListAsync(); + var list = await s.ListAsync().DefaultTimeout(); Assert.Collection(list, item => @@ -264,7 +259,7 @@ public async Task VerifyDockerAppWorks() Assert.Equal(["--add-host", "testlocalhost:127.0.0.1"], item.Spec.RunArgs); }); - await app.StopAsync(); + await app.StopAsync().DefaultTimeout(); } [Fact] @@ -285,18 +280,18 @@ public async Task VerifyContainerStopStartWorks() var applicationExecutor = app.Services.GetRequiredService(); var suffix = app.Services.GetRequiredService>().Value.ResourceNameSuffix; - await app.StartAsync(); + await app.StartAsync().DefaultTimeout(); - using var cts = new CancellationTokenSource(Debugger.IsAttached ? Timeout.InfiniteTimeSpan : TimeSpan.FromMinutes(1)); + using var cts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(TestConstants.LongTimeoutDuration); var token = cts.Token; var containerPattern = $"redis0-{ReplicaIdRegex}-{suffix}"; - var redisContainer = await KubernetesHelper.GetResourceByNameMatchAsync(kubernetes, containerPattern, r => r.Status?.State == ContainerState.Running, token); + var redisContainer = await KubernetesHelper.GetResourceByNameMatchAsync(kubernetes, containerPattern, r => r.Status?.State == ContainerState.Running, token).DefaultTimeout(TestConstants.LongTimeoutDuration); Assert.NotNull(redisContainer); - await applicationExecutor.StopResourceAsync(redisContainer.Metadata.Name, token); + await applicationExecutor.StopResourceAsync(redisContainer.Metadata.Name, token).DefaultTimeout(); - redisContainer = await KubernetesHelper.GetResourceByNameMatchAsync(kubernetes, containerPattern, r => r.Status?.State == ContainerState.Exited, token); + redisContainer = await KubernetesHelper.GetResourceByNameMatchAsync(kubernetes, containerPattern, r => r.Status?.State == ContainerState.Exited, token).DefaultTimeout(TestConstants.LongTimeoutDuration); Assert.NotNull(redisContainer); // TODO: Container start has issues in DCP. Waiting for fix. @@ -305,7 +300,7 @@ public async Task VerifyContainerStopStartWorks() //redisContainer = await KubernetesHelper.GetResourceByNameMatchAsync(kubernetes, containerPattern, r => r.Status?.State == ContainerState.Running, token); //Assert.NotNull(redisContainer); - await app.StopAsync(); + await app.StopAsync().DefaultTimeout(); } [Fact] @@ -322,26 +317,23 @@ public async Task VerifyExecutableStopStartWorks() var applicationExecutor = app.Services.GetRequiredService(); var suffix = app.Services.GetRequiredService>().Value.ResourceNameSuffix; - await app.StartAsync(); - - using var cts = new CancellationTokenSource(Debugger.IsAttached ? Timeout.InfiniteTimeSpan : TimeSpan.FromMinutes(1)); - var token = cts.Token; + await app.StartAsync().DefaultTimeout(); var executablePattern = $"servicea-{ReplicaIdRegex}-{suffix}"; - var serviceA = await KubernetesHelper.GetResourceByNameMatchAsync(kubernetes, executablePattern, r => r.Status?.State == ExecutableState.Running, token); + var serviceA = await KubernetesHelper.GetResourceByNameMatchAsync(kubernetes, executablePattern, r => r.Status?.State == ExecutableState.Running).DefaultTimeout(TestConstants.LongTimeoutDuration); Assert.NotNull(serviceA); - await applicationExecutor.StopResourceAsync(serviceA.Metadata.Name, token); + await applicationExecutor.StopResourceAsync(serviceA.Metadata.Name, CancellationToken.None).DefaultTimeout(); - serviceA = await KubernetesHelper.GetResourceByNameMatchAsync(kubernetes, executablePattern, r => r.Status?.State == ExecutableState.Finished, token); + serviceA = await KubernetesHelper.GetResourceByNameMatchAsync(kubernetes, executablePattern, r => r.Status?.State == ExecutableState.Finished).DefaultTimeout(TestConstants.LongTimeoutDuration); Assert.NotNull(serviceA); - await applicationExecutor.StartResourceAsync(serviceA.Metadata.Name, token); + await applicationExecutor.StartResourceAsync(serviceA.Metadata.Name, CancellationToken.None).DefaultTimeout(); - serviceA = await KubernetesHelper.GetResourceByNameMatchAsync(kubernetes, executablePattern, r => r.Status?.State == ExecutableState.Running, token); + serviceA = await KubernetesHelper.GetResourceByNameMatchAsync(kubernetes, executablePattern, r => r.Status?.State == ExecutableState.Running).DefaultTimeout(TestConstants.LongTimeoutDuration); Assert.NotNull(serviceA); - await app.StopAsync(); + await app.StopAsync().DefaultTimeout(); } [Fact] @@ -366,19 +358,16 @@ public async Task SpecifyingEnvPortInEndpointFlowsToEnv() var kubernetes = app.Services.GetRequiredService(); - await app.StartAsync(); - - using var cts = new CancellationTokenSource(Debugger.IsAttached ? Timeout.InfiniteTimeSpan : TimeSpan.FromMinutes(1)); - var token = cts.Token; + await app.StartAsync().DefaultTimeout(); var suffix = app.Services.GetRequiredService>().Value.ResourceNameSuffix; - var redisContainer = await KubernetesHelper.GetResourceByNameMatchAsync(kubernetes, $"redis0-{ReplicaIdRegex}-{suffix}", r => r.Status?.EffectiveEnv is not null, token); + var redisContainer = await KubernetesHelper.GetResourceByNameMatchAsync(kubernetes, $"redis0-{ReplicaIdRegex}-{suffix}", r => r.Status?.EffectiveEnv is not null).DefaultTimeout(); Assert.NotNull(redisContainer); - var serviceA = await KubernetesHelper.GetResourceByNameAsync(kubernetes, "servicea", suffix!, r => r.Status?.EffectiveEnv is not null, token); + var serviceA = await KubernetesHelper.GetResourceByNameAsync(kubernetes, "servicea", suffix!, r => r.Status?.EffectiveEnv is not null).DefaultTimeout(); Assert.NotNull(serviceA); - var nodeApp = await KubernetesHelper.GetResourceByNameMatchAsync(kubernetes, $"nodeapp-{ReplicaIdRegex}-{suffix}", r => r.Status?.EffectiveEnv is not null, token); + var nodeApp = await KubernetesHelper.GetResourceByNameMatchAsync(kubernetes, $"nodeapp-{ReplicaIdRegex}-{suffix}", r => r.Status?.EffectiveEnv is not null).DefaultTimeout(); Assert.NotNull(nodeApp); Assert.Equal("redis:latest", redisContainer.Spec.Image); @@ -395,7 +384,7 @@ public async Task SpecifyingEnvPortInEndpointFlowsToEnv() Assert.False(string.IsNullOrEmpty(nodeAppPortValue)); Assert.NotEqual(0, int.Parse(nodeAppPortValue, CultureInfo.InvariantCulture)); - await app.StopAsync(); + await app.StopAsync().DefaultTimeout(); static string? GetEnv(IEnumerable? envVars, string name) { @@ -422,13 +411,10 @@ public async Task StartAsync_DashboardAuthConfig_PassedToDashboardProcess() var kubernetes = app.Services.GetRequiredService(); - await app.StartAsync(); - - using var cts = new CancellationTokenSource(Debugger.IsAttached ? Timeout.InfiniteTimeSpan : TimeSpan.FromSeconds(10)); - var token = cts.Token; + await app.StartAsync().DefaultTimeout(); var suffix = app.Services.GetRequiredService>().Value.ResourceNameSuffix; - var aspireDashboard = await KubernetesHelper.GetResourceByNameMatchAsync(kubernetes, $"aspire-dashboard-{ReplicaIdRegex}-{suffix}", r => r.Status?.EffectiveEnv is not null, token); + var aspireDashboard = await KubernetesHelper.GetResourceByNameMatchAsync(kubernetes, $"aspire-dashboard-{ReplicaIdRegex}-{suffix}", r => r.Status?.EffectiveEnv is not null).DefaultTimeout(); Assert.NotNull(aspireDashboard); Assert.Equal("BrowserToken", GetEnv(aspireDashboard.Spec.Env, "DASHBOARD__FRONTEND__AUTHMODE")); @@ -438,7 +424,7 @@ public async Task StartAsync_DashboardAuthConfig_PassedToDashboardProcess() var keyBytes = Convert.FromHexString(GetEnv(aspireDashboard.Spec.Env, "DASHBOARD__OTLP__PRIMARYAPIKEY")!); Assert.Equal(16, keyBytes.Length); - await app.StopAsync(); + await app.StopAsync().DefaultTimeout(); static string? GetEnv(IEnumerable? envVars, string name) { @@ -464,19 +450,16 @@ public async Task StartAsync_UnsecuredAllowAnonymous_PassedToDashboardProcess() var kubernetes = app.Services.GetRequiredService(); - await app.StartAsync(); - - using var cts = new CancellationTokenSource(Debugger.IsAttached ? Timeout.InfiniteTimeSpan : TimeSpan.FromSeconds(10)); - var token = cts.Token; + await app.StartAsync().DefaultTimeout(); var suffix = app.Services.GetRequiredService>().Value.ResourceNameSuffix; - var aspireDashboard = await KubernetesHelper.GetResourceByNameMatchAsync(kubernetes, $"aspire-dashboard-{ReplicaIdRegex}-{suffix}", r => r.Status?.EffectiveEnv is not null, token); + var aspireDashboard = await KubernetesHelper.GetResourceByNameMatchAsync(kubernetes, $"aspire-dashboard-{ReplicaIdRegex}-{suffix}", r => r.Status?.EffectiveEnv is not null).DefaultTimeout(); Assert.NotNull(aspireDashboard); Assert.Equal("Unsecured", GetEnv(aspireDashboard.Spec.Env, "DASHBOARD__FRONTEND__AUTHMODE")); Assert.Equal("Unsecured", GetEnv(aspireDashboard.Spec.Env, "DASHBOARD__OTLP__AUTHMODE")); - await app.StopAsync(); + await app.StopAsync().DefaultTimeout(); static string? GetEnv(IEnumerable? envVars, string name) { @@ -498,23 +481,19 @@ public async Task VerifyDockerWithEntrypointWorks() await using var app = testProgram.Build(); - await app.StartAsync(); + await app.StartAsync().DefaultTimeout(); var s = app.Services.GetRequiredService(); - using var cts = new CancellationTokenSource(Debugger.IsAttached ? Timeout.InfiniteTimeSpan : TimeSpan.FromMinutes(1)); - var token = cts.Token; - var suffix = app.Services.GetRequiredService>().Value.ResourceNameSuffix; var redisContainer = await KubernetesHelper.GetResourceByNameMatchAsync(s, $"redis-cli-{ReplicaIdRegex}-{suffix}", - r => r.Status?.State == ContainerState.FailedToStart && (r.Status?.Message.Contains("bob") ?? false), - token); + r => r.Status?.State == ContainerState.FailedToStart && (r.Status?.Message.Contains("bob") ?? false)).DefaultTimeout(TestConstants.LongTimeoutDuration); Assert.NotNull(redisContainer); Assert.Equal("redis:latest", redisContainer.Spec.Image); Assert.Equal("bob", redisContainer.Spec.Command); - await app.StopAsync(); + await app.StopAsync().DefaultTimeout(); } [Fact] @@ -531,24 +510,20 @@ public async Task VerifyDockerWithBindMountWorksWithAbsolutePaths() await using var app = testProgram.Build(); - await app.StartAsync(); + await app.StartAsync().DefaultTimeout(); var s = app.Services.GetRequiredService(); - using var cts = new CancellationTokenSource(Debugger.IsAttached ? Timeout.InfiniteTimeSpan : TimeSpan.FromMinutes(1)); - var token = cts.Token; - var suffix = app.Services.GetRequiredService>().Value.ResourceNameSuffix; var redisContainer = await KubernetesHelper.GetResourceByNameMatchAsync( s, - $"redis-cli-{ReplicaIdRegex}-{suffix}", r => r.Spec.VolumeMounts != null, - token); + $"redis-cli-{ReplicaIdRegex}-{suffix}", r => r.Spec.VolumeMounts != null).DefaultTimeout(); Assert.NotNull(redisContainer.Spec.VolumeMounts); Assert.NotEmpty(redisContainer.Spec.VolumeMounts); Assert.Equal(sourcePath, redisContainer.Spec.VolumeMounts[0].Source); - await app.StopAsync(); + await app.StopAsync().DefaultTimeout(); } [Fact] @@ -564,25 +539,21 @@ public async Task VerifyDockerWithBindMountWorksWithRelativePaths() await using var app = testProgram.Build(); - await app.StartAsync(); + await app.StartAsync().DefaultTimeout(); var s = app.Services.GetRequiredService(); - using var cts = new CancellationTokenSource(Debugger.IsAttached ? Timeout.InfiniteTimeSpan : TimeSpan.FromMinutes(1)); - var token = cts.Token; - var suffix = app.Services.GetRequiredService>().Value.ResourceNameSuffix; var redisContainer = await KubernetesHelper.GetResourceByNameMatchAsync( s, - $"redis-cli-{ReplicaIdRegex}-{suffix}", r => r.Spec.VolumeMounts != null, - token); + $"redis-cli-{ReplicaIdRegex}-{suffix}", r => r.Spec.VolumeMounts != null).DefaultTimeout(); Assert.NotNull(redisContainer.Spec.VolumeMounts); Assert.NotEmpty(redisContainer.Spec.VolumeMounts); Assert.NotEqual("etc/path-here", redisContainer.Spec.VolumeMounts[0].Source); Assert.True(Path.IsPathRooted(redisContainer.Spec.VolumeMounts[0].Source)); - await app.StopAsync(); + await app.StopAsync().DefaultTimeout(); } [Fact] @@ -598,24 +569,20 @@ public async Task VerifyDockerWithVolumeWorksWithName() await using var app = testProgram.Build(); - await app.StartAsync(); + await app.StartAsync().DefaultTimeout(); var s = app.Services.GetRequiredService(); - using var cts = new CancellationTokenSource(Debugger.IsAttached ? Timeout.InfiniteTimeSpan : TimeSpan.FromMinutes(1)); - var token = cts.Token; - var suffix = app.Services.GetRequiredService>().Value.ResourceNameSuffix; var redisContainer = await KubernetesHelper.GetResourceByNameMatchAsync( s, - $"redis-cli-{ReplicaIdRegex}-{suffix}", r => r.Spec.VolumeMounts != null, - token); + $"redis-cli-{ReplicaIdRegex}-{suffix}", r => r.Spec.VolumeMounts != null).DefaultTimeout(); Assert.NotNull(redisContainer.Spec.VolumeMounts); Assert.NotEmpty(redisContainer.Spec.VolumeMounts); Assert.Equal("test-volume-name", redisContainer.Spec.VolumeMounts[0].Source); - await app.StopAsync(); + await app.StopAsync().DefaultTimeout(); } [Fact] @@ -628,13 +595,10 @@ public async Task KubernetesHasResourceNameForContainersAndExes() await using var app = testProgram.Build(); - await app.StartAsync(); + await app.StartAsync().DefaultTimeout(); var s = app.Services.GetRequiredService(); - using var cts = new CancellationTokenSource(Debugger.IsAttached ? Timeout.InfiniteTimeSpan : TimeSpan.FromMinutes(1)); - var token = cts.Token; - var expectedExeResources = new HashSet() { "servicea", @@ -652,7 +616,7 @@ public async Task KubernetesHasResourceNameForContainersAndExes() "eventhubns" }; - await foreach (var resource in s.WatchAsync(cancellationToken: token)) + await foreach (var resource in s.WatchAsync().DefaultTimeout()) { Assert.True(resource.Item2.Metadata.Annotations.TryGetValue(Container.ResourceNameAnnotation, out var value)); if (expectedContainerResources.Contains(value)) @@ -666,7 +630,7 @@ public async Task KubernetesHasResourceNameForContainersAndExes() } } - await foreach (var resource in s.WatchAsync(cancellationToken: token)) + await foreach (var resource in s.WatchAsync().DefaultTimeout()) { Assert.True(resource.Item2.Metadata.Annotations.TryGetValue(Executable.ResourceNameAnnotation, out var value)); if (expectedExeResources.Contains(value)) @@ -694,7 +658,7 @@ public async Task ReplicasAndProxylessEndpointThrows() await using var app = testProgram.Build(); - var ex = await Assert.ThrowsAsync(() => app.StartAsync()); + var ex = await Assert.ThrowsAsync(() => app.StartAsync()).DefaultTimeout(); var suffix = app.Services.GetRequiredService>().Value.ResourceNameSuffix; Assert.Equal($"Resource 'servicea-{suffix}' uses multiple replicas and a proxy-less endpoint 'http'. These features do not work together.", ex.Message); } @@ -713,7 +677,7 @@ public async Task ProxylessEndpointWithoutPortThrows() await using var app = testProgram.Build(); - var ex = await Assert.ThrowsAsync(() => app.StartAsync()); + var ex = await Assert.ThrowsAsync(() => app.StartAsync()).DefaultTimeout(); var suffix = app.Services.GetRequiredService>().Value.ResourceNameSuffix; Assert.Equal($"Service 'servicea-{suffix}' needs to specify a port for endpoint 'http' since it isn't using a proxy.", ex.Message); } @@ -734,20 +698,23 @@ public async Task ProxylessEndpointWorks() testProgram.AppBuilder.Services.AddLogging(b => b.AddXunit(_testOutputHelper)); await using var app = testProgram.Build(); - await app.StartAsync(); + await app.StartAsync().DefaultTimeout(); var client = app.CreateHttpClientWithResilience("servicea", "http"); - using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1)); - var result = await client.GetStringAsync("pid", cts.Token); + var result = await client.GetStringAsync("pid").DefaultTimeout(TestConstants.LongTimeoutDuration); Assert.NotNull(result); // Check that endpoint from launchsettings doesn't work await Assert.ThrowsAnyAsync(async () => { - using var client2 = new HttpClient(); + using var client2 = new HttpClient(new SocketsHttpHandler + { + // Provide a timeout to avoid long timeout while trying to connect. + ConnectTimeout = TimeSpan.FromSeconds(2) + }); await client2.GetStringAsync("http://localhost:5156/pid"); - }); + }).DefaultTimeout(); } [Fact] @@ -773,9 +740,10 @@ public async Task ProxylessAndProxiedEndpointBothWorkOnSameResource() await using var app = testProgram.Build(); - await app.StartAsync(); + await app.StartAsync().DefaultTimeout(); - var token = new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token; + using var cts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(TestConstants.LongTimeoutDuration); + var token = cts.Token; var urls = string.Empty; var httpEndPoint = app.GetEndpoint(testProgram.ServiceABuilder.Resource.Name, endpointName: "http"); @@ -804,7 +772,7 @@ public async Task ProxylessAndProxiedEndpointBothWorkOnSameResource() try { using var client = new HttpClient(); - var value = await client.GetStringAsync($"{httpsEndpoint}urls", token); + var value = await client.GetStringAsync($"{httpsEndpoint}urls", token).DefaultTimeout(); Assert.Equal(urls, value); break; } @@ -837,17 +805,17 @@ public async Task ProxylessContainerCanBeReferenced() .WithReference(redisNoPort); using var app = builder.Build(); - await app.StartAsync(); + await app.StartAsync().DefaultTimeout(); // Wait for the application to be ready - await app.WaitForTextAsync("Application started.").WaitAsync(TimeSpan.FromMinutes(1)); + await app.WaitForTextAsync("Application started.").DefaultTimeout(); // Wait until the service itself starts. using var clientA = app.CreateHttpClient(servicea.Resource.Name, "http"); - await clientA.GetStringAsync("/"); + await clientA.GetStringAsync("/").DefaultTimeout(); var s = app.Services.GetRequiredService(); - var exeList = await s.ListAsync(); + var exeList = await s.ListAsync().DefaultTimeout(); var suffix = app.Services.GetRequiredService>().Value.ResourceNameSuffix; Assert.NotNull(suffix); @@ -855,7 +823,7 @@ public async Task ProxylessContainerCanBeReferenced() var env = Assert.Single(service.Spec.Env!.Where(e => e.Name == "ConnectionStrings__redis")); Assert.Equal("localhost:1234", env.Value); - var list = await s.ListAsync(); + var list = await s.ListAsync().DefaultTimeout(); var redisContainer = Assert.Single(list.Where(c => Regex.IsMatch(c.Name(),$"redis-{ReplicaIdRegex}-{suffix}"))) ; Assert.Equal(1234, Assert.Single(redisContainer.Spec.Ports!).HostPort); @@ -865,7 +833,7 @@ public async Task ProxylessContainerCanBeReferenced() var otherRedisContainer = Assert.Single(list.Where(c => Regex.IsMatch(c.Name(), $"redisNoPort-{ReplicaIdRegex}-{suffix}"))); Assert.Equal(6379, Assert.Single(otherRedisContainer.Spec.Ports!).HostPort); - await app.StopAsync(); + await app.StopAsync().DefaultTimeout(); } [Fact] @@ -882,7 +850,7 @@ public async Task ProxylessContainerWithoutPortThrows() using var app = builder.Build(); - var ex = await Assert.ThrowsAsync(() => app.StartAsync()); + var ex = await Assert.ThrowsAsync(() => app.StartAsync()).DefaultTimeout(); var suffix = app.Services.GetRequiredService>().Value.ResourceNameSuffix; Assert.Equal($"The endpoint 'tcp' for container resource 'dummyRedis-{suffix}' must specify the TargetPort value", ex.Message); } @@ -904,9 +872,9 @@ public async Task AfterResourcesCreatedLifecycleHookWorks() var kubernetesLifecycle = (KubernetesTestLifecycleHook)lifecycles.Where(l => l.GetType() == typeof(KubernetesTestLifecycleHook)).First(); kubernetesLifecycle.KubernetesService = s; - await app.StartAsync(); + await app.StartAsync().DefaultTimeout(); - await kubernetesLifecycle.HooksCompleted; + await kubernetesLifecycle.HooksCompleted.DefaultTimeout(); } private sealed class KubernetesTestLifecycleHook : IDistributedApplicationLifecycleHook diff --git a/tests/Aspire.Hosting.Tests/Eventing/DistributedApplicationBuilderEventingTests.cs b/tests/Aspire.Hosting.Tests/Eventing/DistributedApplicationBuilderEventingTests.cs index 11b9c6fe975..591963386e0 100644 --- a/tests/Aspire.Hosting.Tests/Eventing/DistributedApplicationBuilderEventingTests.cs +++ b/tests/Aspire.Hosting.Tests/Eventing/DistributedApplicationBuilderEventingTests.cs @@ -4,6 +4,7 @@ using Aspire.Components.Common.Tests; using Aspire.Hosting.Eventing; using Aspire.Hosting.Utils; +using Microsoft.AspNetCore.InternalTesting; using Microsoft.Extensions.DependencyInjection; using Xunit; @@ -35,10 +36,10 @@ public async Task EventsCanBePublishedBlockSequential() var pendingPublish = builder.Eventing.PublishAsync(new DummyEvent(), EventDispatchBehavior.BlockingSequential); - await blockAssertionTcs.Task; + await blockAssertionTcs.Task.DefaultTimeout(); Assert.Equal(1, hitCount); blockFirstSubscriptionTcs.SetResult(); - await pendingPublish; + await pendingPublish.DefaultTimeout(); Assert.Equal(2, hitCount); } @@ -68,10 +69,10 @@ public async Task EventsCanBePublishedBlockConcurrent() var pendingPublish = builder.Eventing.PublishAsync(new DummyEvent(), EventDispatchBehavior.BlockingConcurrent); - await Task.WhenAll(blockAssertionSub1.Task, blockAssertionSub2.Task); + await Task.WhenAll(blockAssertionSub1.Task, blockAssertionSub2.Task).DefaultTimeout(); Assert.Equal(2, hitCount); blockSubscriptionCompletion.SetResult(); - await pendingPublish; + await pendingPublish.DefaultTimeout(); } [Fact] @@ -98,11 +99,10 @@ public async Task EventsCanBePublishedNonBlockingConcurrent() blockAssertionSub2.SetResult(); }); - var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); // Should be way more than we need! - await builder.Eventing.PublishAsync(new DummyEvent(), EventDispatchBehavior.NonBlockingConcurrent, timeoutCts.Token); + await builder.Eventing.PublishAsync(new DummyEvent(), EventDispatchBehavior.NonBlockingConcurrent).DefaultTimeout(); blockSubscriptionExecution.SetResult(); - await Task.WhenAll(blockAssertionSub1.Task, blockAssertionSub2.Task); + await Task.WhenAll(blockAssertionSub1.Task, blockAssertionSub2.Task).DefaultTimeout(); Assert.Equal(2, hitCount); } @@ -134,12 +134,11 @@ public async Task EventsCanBePublishedNonBlockingSequential() return Task.CompletedTask; }); - var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); // Should be way more than we need! - await builder.Eventing.PublishAsync(new DummyEvent(), EventDispatchBehavior.NonBlockingSequential, timeoutCts.Token); + await builder.Eventing.PublishAsync(new DummyEvent(), EventDispatchBehavior.NonBlockingSequential).DefaultTimeout(); // Make sure that we are zero when we enter // the first handler. - await blockAssert1.Task; + await blockAssert1.Task.DefaultTimeout(); Assert.Equal(0, hitCount); // Give the second handler a chance to run, @@ -152,13 +151,13 @@ public async Task EventsCanBePublishedNonBlockingSequential() // we update the hit count and verify // that it has moved to 1. blockEventSub1.SetResult(); - await blockAssert2.Task; + await blockAssert2.Task.DefaultTimeout(); Assert.Equal(1, hitCount); blockEventSub2.SetResult(); // Now block until the second handler has // run and make sure it has incremented. - await blockAssert3.Task; + await blockAssert3.Task.DefaultTimeout(); Assert.Equal(2, hitCount); } @@ -175,7 +174,7 @@ public void CanResolveIDistributedApplicationEventingFromDI() [RequiresDocker] public async Task ResourceEventsForContainersFireForSpecificResources() { - var beforeResourceStartedEvent = new ManualResetEventSlim(); + var beforeResourceStartedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); using var builder = TestDistributedApplicationBuilder.Create(); var redis = builder.AddRedis("redis"); @@ -184,17 +183,16 @@ public async Task ResourceEventsForContainersFireForSpecificResources() { Assert.NotNull(e.Services); Assert.NotNull(e.Resource); - beforeResourceStartedEvent.Set(); + beforeResourceStartedTcs.TrySetResult(); return Task.CompletedTask; }); using var app = builder.Build(); - await app.StartAsync(); + await app.StartAsync().DefaultTimeout(); - var fired = beforeResourceStartedEvent.Wait(TimeSpan.FromSeconds(10)); + await beforeResourceStartedTcs.Task.DefaultTimeout(); - Assert.True(fired); - await app.StopAsync(); + await app.StopAsync().DefaultTimeout(); } [Fact] diff --git a/tests/Aspire.Hosting.Tests/ExecutableResourceTests.cs b/tests/Aspire.Hosting.Tests/ExecutableResourceTests.cs index 794900eb992..c1462fbecc1 100644 --- a/tests/Aspire.Hosting.Tests/ExecutableResourceTests.cs +++ b/tests/Aspire.Hosting.Tests/ExecutableResourceTests.cs @@ -3,6 +3,7 @@ using Aspire.Hosting.Tests.Utils; using Aspire.Hosting.Utils; +using Microsoft.AspNetCore.InternalTesting; using Xunit; namespace Aspire.Hosting.Tests; @@ -35,7 +36,7 @@ public async Task AddExecutableWithArgs() using var app = appBuilder.Build(); - var args = await ArgumentEvaluator.GetArgumentListAsync(exe2.Resource); + var args = await ArgumentEvaluator.GetArgumentListAsync(exe2.Resource).DefaultTimeout(); Assert.Collection(args, arg => Assert.Equal("app.py", arg), @@ -47,7 +48,7 @@ public async Task AddExecutableWithArgs() arg => Assert.Equal("anotherConnectionString", arg) ); - var manifest = await ManifestUtils.GetManifest(exe2.Resource); + var manifest = await ManifestUtils.GetManifest(exe2.Resource).DefaultTimeout(); var expectedManifest = """ diff --git a/tests/Aspire.Hosting.Tests/ExpressionResolverTests.cs b/tests/Aspire.Hosting.Tests/ExpressionResolverTests.cs index 03eefe5d5c0..37e1c3566d7 100644 --- a/tests/Aspire.Hosting.Tests/ExpressionResolverTests.cs +++ b/tests/Aspire.Hosting.Tests/ExpressionResolverTests.cs @@ -2,9 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Hosting.Tests.Utils; +using Microsoft.AspNetCore.InternalTesting; using Xunit; namespace Aspire.Hosting.Tests; + public class ExpressionResolverTests { [Theory] @@ -49,7 +51,7 @@ public async Task ExpressionResolverGeneratesCorrectStrings(string exprName, boo // First test ExpressionResolver directly var csRef = new ConnectionStringReference(target.Resource, false); - var connectionString = await ExpressionResolver.ResolveAsync(sourceIsContainer, csRef, "ContainerHostName", CancellationToken.None); + var connectionString = await ExpressionResolver.ResolveAsync(sourceIsContainer, csRef, "ContainerHostName", CancellationToken.None).DefaultTimeout(); Assert.Equal(expectedConnectionString, connectionString); // Then test it indirectly with a resource reference, which exercises a more complete code path @@ -60,7 +62,7 @@ public async Task ExpressionResolverGeneratesCorrectStrings(string exprName, boo source = source.WithImage("someimage"); } - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(source.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance, "ContainerHostName"); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(source.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance, "ContainerHostName").DefaultTimeout(); Assert.Equal(expectedConnectionString, config["ConnectionStrings__testresource"]); } @@ -92,7 +94,7 @@ public async Task HostUrlPropertyGetsResolved(bool container, string hostUrlVal, test = test.WithImage("someimage"); } - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(test.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance, "ContainerHostName"); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(test.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance, "ContainerHostName").DefaultTimeout(); Assert.Equal(expectedValue, config["envname"]); } @@ -111,7 +113,7 @@ public async Task HostUrlPropertyGetsResolvedInOtlpExporterEndpoint(bool contain test = test.WithImage("someimage"); } - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(test.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance, "ContainerHostName"); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(test.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance, "ContainerHostName").DefaultTimeout(); Assert.Equal(expectedValue, config["OTEL_EXPORTER_OTLP_ENDPOINT"]); } } diff --git a/tests/Aspire.Hosting.Tests/Health/ResourceHealthCheckServiceTests.cs b/tests/Aspire.Hosting.Tests/Health/ResourceHealthCheckServiceTests.cs index 507eef4cb3a..70bff832525 100644 --- a/tests/Aspire.Hosting.Tests/Health/ResourceHealthCheckServiceTests.cs +++ b/tests/Aspire.Hosting.Tests/Health/ResourceHealthCheckServiceTests.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using Aspire.Hosting.Utils; +using Microsoft.AspNetCore.InternalTesting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Xunit; @@ -18,17 +19,17 @@ public async Task ResourcesWithoutHealthCheck_HealthyWhenRunning() using var builder = TestDistributedApplicationBuilder.Create(testOutputHelper); var resource = builder.AddResource(new ParentResource("resource")); - await using var app = await builder.BuildAsync(); + await using var app = await builder.BuildAsync().DefaultTimeout(); var rns = app.Services.GetRequiredService(); - await app.StartAsync(); + await app.StartAsync().DefaultTimeout(); await rns.PublishUpdateAsync(resource.Resource, s => s with { State = new ResourceStateSnapshot(KnownResourceStates.Starting, null) - }); + }).DefaultTimeout(); - var startingEvent = await rns.WaitForResourceAsync("resource", e => e.Snapshot.State?.Text == KnownResourceStates.Starting); + var startingEvent = await rns.WaitForResourceAsync("resource", e => e.Snapshot.State?.Text == KnownResourceStates.Starting).DefaultTimeout(); Assert.Null(startingEvent.Snapshot.HealthStatus); await rns.PublishUpdateAsync(resource.Resource, s => s with @@ -36,10 +37,10 @@ await rns.PublishUpdateAsync(resource.Resource, s => s with State = new ResourceStateSnapshot(KnownResourceStates.Running, null) }); - var healthyEvent = await rns.WaitForResourceHealthyAsync("resource"); + var healthyEvent = await rns.WaitForResourceHealthyAsync("resource").DefaultTimeout(); Assert.Equal(HealthStatus.Healthy, healthyEvent.Snapshot.HealthStatus); - await app.StopAsync(); + await app.StopAsync().DefaultTimeout(); } [Fact] @@ -52,17 +53,17 @@ public async Task ResourcesWithHealthCheck_NotHealthyUntilCheckSucceeds() var resource = builder.AddResource(new ParentResource("resource")) .WithHealthCheck("healthcheck_a"); - await using var app = await builder.BuildAsync(); + await using var app = await builder.BuildAsync().DefaultTimeout(); var rns = app.Services.GetRequiredService(); - await app.StartAsync(); + await app.StartAsync().DefaultTimeout(); await rns.PublishUpdateAsync(resource.Resource, s => s with { State = new ResourceStateSnapshot(KnownResourceStates.Starting, null) - }); + }).DefaultTimeout(); - var startingEvent = await rns.WaitForResourceAsync("resource", e => e.Snapshot.State?.Text == KnownResourceStates.Starting); + var startingEvent = await rns.WaitForResourceAsync("resource", e => e.Snapshot.State?.Text == KnownResourceStates.Starting).DefaultTimeout(); Assert.Null(startingEvent.Snapshot.HealthStatus); await rns.PublishUpdateAsync(resource.Resource, s => s with @@ -70,12 +71,12 @@ await rns.PublishUpdateAsync(resource.Resource, s => s with State = new ResourceStateSnapshot(KnownResourceStates.Running, null) }); - var runningEvent = await rns.WaitForResourceAsync("resource", e => e.Snapshot.State?.Text == KnownResourceStates.Running); + var runningEvent = await rns.WaitForResourceAsync("resource", e => e.Snapshot.State?.Text == KnownResourceStates.Running).DefaultTimeout(); Assert.Equal(HealthStatus.Unhealthy, runningEvent.Snapshot.HealthStatus); - await rns.WaitForResourceHealthyAsync("resource"); + await rns.WaitForResourceHealthyAsync("resource").DefaultTimeout(); - await app.StopAsync(); + await app.StopAsync().DefaultTimeout(); } [Fact] @@ -98,15 +99,15 @@ public async Task HealthCheckIntervalSlowsAfterSteadyHealthyState() using var app = builder.Build(); var rns = app.Services.GetRequiredService(); - var abortTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(120)); + var abortTokenSource = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(TestConstants.LongTimeoutDuration); - await app.StartAsync(abortTokenSource.Token); + await app.StartAsync(abortTokenSource.Token).DefaultTimeout(); await rns.PublishUpdateAsync(resource.Resource, s => s with { State = KnownResourceStates.Running - }); - await rns.WaitForResourceHealthyAsync(resource.Resource.Name, abortTokenSource.Token); + }).DefaultTimeout(); + await rns.WaitForResourceHealthyAsync(resource.Resource.Name, abortTokenSource.Token).DefaultTimeout(); are = new AutoResetEvent(false); @@ -120,7 +121,7 @@ await rns.PublishUpdateAsync(resource.Resource, s => s with // Delay is 30 seconds but we allow for a (ridiculous) 10 second margin of error. Assert.True(stopwatch.ElapsedMilliseconds > 20000); - await app.StopAsync(abortTokenSource.Token); + await app.StopAsync(abortTokenSource.Token).DefaultTimeout(); } [Fact] @@ -143,15 +144,15 @@ public async Task HealthCheckIntervalDoesNotSlowBeforeSteadyHealthyState() using var app = builder.Build(); var rns = app.Services.GetRequiredService(); - var abortTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(120)); + var abortTokenSource = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(TestConstants.LongTimeoutDuration); - await app.StartAsync(abortTokenSource.Token); + await app.StartAsync(abortTokenSource.Token).DefaultTimeout(); await rns.PublishUpdateAsync(resource.Resource, s => s with { State = KnownResourceStates.Running - }); - await rns.WaitForResourceAsync(resource.Resource.Name, KnownResourceStates.Running, abortTokenSource.Token); + }).DefaultTimeout(); + await rns.WaitForResourceAsync(resource.Resource.Name, KnownResourceStates.Running, abortTokenSource.Token).DefaultTimeout(); are = new AutoResetEvent(false); @@ -167,7 +168,7 @@ await rns.PublishUpdateAsync(resource.Resource, s => s with // the 30 second slow path. Assert.True(stopwatch.ElapsedMilliseconds < 10000); - await app.StopAsync(abortTokenSource.Token); + await app.StopAsync(abortTokenSource.Token).DefaultTimeout(); } [Fact] @@ -190,13 +191,13 @@ public async Task ResourcesWithoutHealthCheckAnnotationsGetReadyEventFired() await rns.PublishUpdateAsync(resource.Resource, s => s with { State = new ResourceStateSnapshot(KnownResourceStates.Running, null) - }); + }).DefaultTimeout(); - var @event = await blockAssert.Task; + var @event = await blockAssert.Task.DefaultTimeout(); Assert.Equal(resource.Resource, @event.Resource); - await pendingStart; - await app.StopAsync(); + await pendingStart.DefaultTimeout(); + await app.StopAsync().DefaultTimeout(); } [Fact] @@ -217,15 +218,14 @@ public async Task PoorlyImplementedHealthChecksDontCauseMonitoringLoopToCrashout using var app = builder.Build(); var rns = app.Services.GetRequiredService(); - var abortTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(120)); - var pendingStart = app.StartAsync(abortTokenSource.Token); + var pendingStart = app.StartAsync().DefaultTimeout(); await rns.PublishUpdateAsync(resource.Resource, s => s with { State = new ResourceStateSnapshot(KnownResourceStates.Running, null) - }); + }).DefaultTimeout(); - while (!abortTokenSource.Token.IsCancellationRequested) + while (!pendingStart.IsCanceled) { if (hitCount > 2) { @@ -234,8 +234,8 @@ await rns.PublishUpdateAsync(resource.Resource, s => s with await Task.Delay(100); } - await pendingStart; - await app.StopAsync(); + await pendingStart; // already has a timeout + await app.StopAsync().DefaultTimeout(); } [Fact] @@ -264,12 +264,8 @@ public async Task ResourceHealthCheckServiceDoesNotRunHealthChecksUnlessResource return Task.CompletedTask; }); - // Make sure that this test doesn't run longer than a minute (should finish in a second or two) - // but allow enough time to debug things without having to adjust timings. - var abortTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(120)); - using var app = builder.Build(); - var pendingStart = app.StartAsync(abortTokenSource.Token); + var pendingStart = app.StartAsync().DefaultTimeout(TestConstants.LongTimeoutDuration); var rns = app.Services.GetRequiredService(); // Verify that the health check does not get run before we move the resource into the @@ -277,7 +273,7 @@ public async Task ResourceHealthCheckServiceDoesNotRunHealthChecksUnlessResource // so I'm just going to spin for up to ten seconds to be sure that no local perf // issues lead to a false pass here. var giveUpAfter = DateTime.Now.AddSeconds(10); - while (!abortTokenSource.Token.IsCancellationRequested) + while (!pendingStart.IsCanceled) { Assert.Equal(0, hitCount); await Task.Delay(100); @@ -287,20 +283,19 @@ public async Task ResourceHealthCheckServiceDoesNotRunHealthChecksUnlessResource break; } } - Assert.False(abortTokenSource.IsCancellationRequested); await rns.PublishUpdateAsync(parent.Resource, s => s with { State = new ResourceStateSnapshot(KnownResourceStates.Running, null) - }); + }).DefaultTimeout(); // Wait for the ResourceReadyEvent checkStatus = HealthCheckResult.Healthy(); - await Task.WhenAll([resourceReadyEventFired.Task]); + await Task.WhenAll([resourceReadyEventFired.Task]).DefaultTimeout(); Assert.True(hitCount > 0); - await pendingStart; - await app.StopAsync(); + await pendingStart; // already has a timeout + await app.StopAsync().DefaultTimeout(); } [Fact] @@ -329,21 +324,17 @@ public async Task ResourceHealthCheckServiceOnlyRaisesResourceReadyOnce() return Task.CompletedTask; }); - // Make sure that this test doesn't run longer than a minute (should finish in a second or two) - // but allow enough time to debug things without having to adjust timings. - var abortTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(120)); - using var app = builder.Build(); - var pendingStart = app.StartAsync(abortTokenSource.Token); + var pendingStart = app.StartAsync().DefaultTimeout(); var rns = app.Services.GetRequiredService(); // Get the custom resource to a running state. await rns.PublishUpdateAsync(parent.Resource, s => s with { State = new ResourceStateSnapshot(KnownResourceStates.Running, null) - }); + }).DefaultTimeout(); - while (!abortTokenSource.Token.IsCancellationRequested) + while (!pendingStart.IsCanceled) { // We wait for this hit count to reach 3 // because it means that we've had a chance @@ -355,11 +346,10 @@ await rns.PublishUpdateAsync(parent.Resource, s => s with await Task.Delay(100); } - Assert.False(abortTokenSource.IsCancellationRequested); Assert.Equal(1, eventHits); - await pendingStart; - await app.StopAsync(); + await pendingStart; // already has a timeout + await app.StopAsync().DefaultTimeout(); } [Fact] @@ -395,7 +385,7 @@ public async Task VerifyThatChildResourceWillBecomeHealthyOnceParentBecomesHealt await rns.PublishUpdateAsync(parent.Resource, s => s with { State = new ResourceStateSnapshot(KnownResourceStates.Running, null) - }); + }).DefaultTimeout(); // ... only need to do this with custom resources, for containers this // is handled by app executor. When we get operators we won't need to do @@ -403,16 +393,16 @@ await rns.PublishUpdateAsync(parent.Resource, s => s with await rns.PublishUpdateAsync(child.Resource, s => s with { State = new ResourceStateSnapshot(KnownResourceStates.Running, null) - }); + }).DefaultTimeout(); - var parentReadyEvent = await parentReady.Task; + var parentReadyEvent = await parentReady.Task.DefaultTimeout(); Assert.Equal(parentReadyEvent.Resource, parent.Resource); - var childReadyEvent = await childReady.Task; + var childReadyEvent = await childReady.Task.DefaultTimeout(); Assert.Equal(childReadyEvent.Resource, child.Resource); - await pendingStart; - await app.StopAsync(); + await pendingStart; // already has a timeout + await app.StopAsync().DefaultTimeout(); } private sealed class ParentResource(string name) : Resource(name) diff --git a/tests/Aspire.Hosting.Tests/HealthCheckTests.cs b/tests/Aspire.Hosting.Tests/HealthCheckTests.cs index b3ecf725982..f36616e9ab2 100644 --- a/tests/Aspire.Hosting.Tests/HealthCheckTests.cs +++ b/tests/Aspire.Hosting.Tests/HealthCheckTests.cs @@ -3,6 +3,7 @@ using Aspire.Components.Common.Tests; using Aspire.Hosting.Utils; +using Microsoft.AspNetCore.InternalTesting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; @@ -28,7 +29,7 @@ public async Task WithHttpHealthCheckThrowsIfReferencingEndpointThatIsNotHttpSch var ex = await Assert.ThrowsAsync(async () => { await app.StartAsync(); - }); + }).DefaultTimeout(); Assert.Equal( "The endpoint 'nonhttp' on resource 'resource' was not using the 'http' scheme.", @@ -50,7 +51,7 @@ public async Task WithHttpsHealthCheckThrowsIfReferencingEndpointThatIsNotHttpsS var ex = await Assert.ThrowsAsync(async () => { await app.StartAsync(); - }); + }).DefaultTimeout(); Assert.Equal( "The endpoint 'nonhttp' on resource 'resource' was not using the 'https' scheme.", @@ -62,7 +63,6 @@ public async Task WithHttpsHealthCheckThrowsIfReferencingEndpointThatIsNotHttpsS [RequiresDocker] public async Task VerifyWithHttpHealthCheckBlocksDependentResources() { - var cts = new CancellationTokenSource(TimeSpan.FromMinutes(10)); using var builder = TestDistributedApplicationBuilder.Create().WithTestAndResourceLogging(testOutputHelper); var healthCheckTcs = new TaskCompletionSource(); @@ -81,23 +81,23 @@ public async Task VerifyWithHttpHealthCheckBlocksDependentResources() using var app = builder.Build(); - var pendingStart = app.StartAsync(cts.Token); + var pendingStart = app.StartAsync(); var rns = app.Services.GetRequiredService(); - await rns.WaitForResourceAsync(resource.Resource.Name, KnownResourceStates.Running, cts.Token); + await rns.WaitForResourceAsync(resource.Resource.Name, KnownResourceStates.Running).DefaultTimeout(TestConstants.LongTimeoutDuration); - await rns.WaitForResourceAsync(dependentResource.Resource.Name, KnownResourceStates.Waiting, cts.Token); + await rns.WaitForResourceAsync(dependentResource.Resource.Name, KnownResourceStates.Waiting).DefaultTimeout(TestConstants.LongTimeoutDuration); healthCheckTcs.SetResult(HealthCheckResult.Healthy()); - await rns.WaitForResourceHealthyAsync(resource.Resource.Name, cts.Token); + await rns.WaitForResourceHealthyAsync(resource.Resource.Name).DefaultTimeout(TestConstants.LongTimeoutDuration); - await rns.WaitForResourceAsync(dependentResource.Resource.Name, KnownResourceStates.Running, cts.Token); + await rns.WaitForResourceAsync(dependentResource.Resource.Name, KnownResourceStates.Running).DefaultTimeout(TestConstants.LongTimeoutDuration); - await pendingStart; + await pendingStart.DefaultTimeout(); - await app.StopAsync(); + await app.StopAsync().DefaultTimeout(); } [Fact] @@ -117,7 +117,7 @@ public async Task BuildThrowsOnMissingHealthCheckRegistration() var ex = await Assert.ThrowsAsync(async () => { await app.StartAsync(); - }); + }).DefaultTimeout(); Assert.Equal("A health check registration is missing. Check logs for more details.", ex.Message); diff --git a/tests/Aspire.Hosting.Tests/Helpers/KubernetesHelper.cs b/tests/Aspire.Hosting.Tests/Helpers/KubernetesHelper.cs index 816f2147817..645290e4a95 100644 --- a/tests/Aspire.Hosting.Tests/Helpers/KubernetesHelper.cs +++ b/tests/Aspire.Hosting.Tests/Helpers/KubernetesHelper.cs @@ -10,7 +10,7 @@ namespace Aspire.Hosting.Tests.Helpers; internal static class KubernetesHelper { - public static async Task GetResourceByNameAsync(IKubernetesService kubernetes, string resourceName, string resourceNameSuffix, Func ready, CancellationToken cancellationToken) where T : CustomResource + public static async Task GetResourceByNameAsync(IKubernetesService kubernetes, string resourceName, string resourceNameSuffix, Func ready, CancellationToken cancellationToken = default) where T : CustomResource { await foreach (var (_, r) in kubernetes.WatchAsync(cancellationToken: cancellationToken)) { @@ -25,7 +25,7 @@ public static async Task GetResourceByNameAsync(IKubernetesService kuberne throw new InvalidOperationException($"Resource {resourceName}, not ready"); } - public static async Task GetResourceByNameMatchAsync(IKubernetesService kubernetes, string resourceNamePattern, Func ready, CancellationToken cancellationToken) where T : CustomResource + public static async Task GetResourceByNameMatchAsync(IKubernetesService kubernetes, string resourceNamePattern, Func ready, CancellationToken cancellationToken = default) where T : CustomResource { await foreach (var (_, r) in kubernetes.WatchAsync(cancellationToken: cancellationToken)) { diff --git a/tests/Aspire.Hosting.Tests/KestrelConfigTests.cs b/tests/Aspire.Hosting.Tests/KestrelConfigTests.cs index 522502f183b..5419dd6e0bb 100644 --- a/tests/Aspire.Hosting.Tests/KestrelConfigTests.cs +++ b/tests/Aspire.Hosting.Tests/KestrelConfigTests.cs @@ -3,6 +3,7 @@ using Aspire.Hosting.Tests.Utils; using Aspire.Hosting.Utils; +using Microsoft.AspNetCore.InternalTesting; using Microsoft.Extensions.DependencyInjection; using Xunit; @@ -37,7 +38,7 @@ public async Task SingleKestrelHttpEndpointIsNamedHttpAndOverridesProfile() AllocateTestEndpoints(resource); - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); // When using Kestrel, we should not be setting ASPNETCORE_URLS at all Assert.False(config.ContainsKey("ASPNETCORE_URLS")); @@ -75,7 +76,7 @@ public async Task KestrelHttpEndpointsAreIgnoredWhenFlagIsSet() AllocateTestEndpoints(resource); - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); // We're ignoring Kestrel, so we should be setting ASPNETCORE_URLS Assert.Equal("http://localhost:port_http;http://localhost:port_ExplicitHttp", config["ASPNETCORE_URLS"]); @@ -140,7 +141,7 @@ public async Task ExplicitEndpointsResultInKestrelOverridesAtRuntime() AllocateTestEndpoints(resource); - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); Assert.Collection( config.Where(envVar => envVar.Key.StartsWith("Kestrel__")), @@ -173,7 +174,7 @@ public async Task VerifyKestrelEndpointManifestGeneration() { var resource = CreateTestProjectResource(); - var manifest = await ManifestUtils.GetManifest(resource); + var manifest = await ManifestUtils.GetManifest(resource).DefaultTimeout(); var expectedManifest = """ { @@ -217,7 +218,7 @@ public async Task VerifyMultipleKestrelEndpointsManifestGeneration() builder.WithHttpEndpoint(5018, name: "ExplicitNoProxyHttp", isProxied: false); }); - var manifest = await ManifestUtils.GetManifest(resource); + var manifest = await ManifestUtils.GetManifest(resource).DefaultTimeout(); // Note that unlike in Run mode, SecondHttpEndpoint is using host * instead of localhost var expectedManifest = """ @@ -288,7 +289,7 @@ public async Task VerifyKestrelEnvVariablesGetOmittedFromManifestIfExcluded() .WithEndpointsInEnvironment(e => e.Name != "ExplicitProxiedHttp"); }); - var manifest = await ManifestUtils.GetManifest(resource); + var manifest = await ManifestUtils.GetManifest(resource).DefaultTimeout(); var expectedEnv = """ { @@ -310,7 +311,7 @@ public async Task VerifyEndpointLevelKestrelProtocol() var resource = CreateTestProjectResource( operation: DistributedApplicationOperation.Publish); - var manifest = await ManifestUtils.GetManifest(resource); + var manifest = await ManifestUtils.GetManifest(resource).DefaultTimeout(); var expectedBindings = """ { diff --git a/tests/Aspire.Hosting.Tests/ManifestGenerationTests.cs b/tests/Aspire.Hosting.Tests/ManifestGenerationTests.cs index 43a0d1c7d29..0b47c442cd0 100644 --- a/tests/Aspire.Hosting.Tests/ManifestGenerationTests.cs +++ b/tests/Aspire.Hosting.Tests/ManifestGenerationTests.cs @@ -8,6 +8,7 @@ using Aspire.Hosting.Redis; using Aspire.Hosting.Tests.Helpers; using Aspire.Hosting.Utils; +using Microsoft.AspNetCore.InternalTesting; using Microsoft.Extensions.DependencyInjection; using Xunit; @@ -96,7 +97,7 @@ public async Task WithContainerRegistryUpdatesContainerImageAnnotationsDuringPub var redis = builder.AddContainer("redis", "redis"); builder.Build().Run(); - var redisManifest = await ManifestUtils.GetManifest(redis.Resource); + var redisManifest = await ManifestUtils.GetManifest(redis.Resource).DefaultTimeout(); var expectedManifest = $$""" { "type": "container.v0", @@ -437,7 +438,7 @@ public void VerifyTestProgramFullManifest() "redis": { "type": "container.v0", "connectionString": "{redis.bindings.tcp.host}:{redis.bindings.tcp.port}", - "image": "{{TestConstants.AspireTestContainerRegistry}}/{{RedisContainerImageTags.Image}}:{{RedisContainerImageTags.Tag}}", + "image": "{{ComponentTestConstants.AspireTestContainerRegistry}}/{{RedisContainerImageTags.Image}}:{{RedisContainerImageTags.Tag}}", "bindings": { "tcp": { "scheme": "tcp", @@ -450,7 +451,7 @@ public void VerifyTestProgramFullManifest() "postgres": { "type": "container.v0", "connectionString": "Host={postgres.bindings.tcp.host};Port={postgres.bindings.tcp.port};Username=postgres;Password={postgres-password.value}", - "image": "{{TestConstants.AspireTestContainerRegistry}}/{{PostgresContainerImageTags.Image}}:{{PostgresContainerImageTags.Tag}}", + "image": "{{ComponentTestConstants.AspireTestContainerRegistry}}/{{PostgresContainerImageTags.Image}}:{{PostgresContainerImageTags.Tag}}", "env": { "POSTGRES_HOST_AUTH_METHOD": "scram-sha-256", "POSTGRES_INITDB_ARGS": "--auth-host=scram-sha-256 --auth-local=scram-sha-256", @@ -552,7 +553,7 @@ public async Task ParameterInputDefaultValuesGenerateCorrectly() } """; - var manifest = await ManifestUtils.GetManifest(param.Resource); + var manifest = await ManifestUtils.GetManifest(param.Resource).DefaultTimeout(); Assert.Equal(expectedManifest, manifest.ToString()); } diff --git a/tests/Aspire.Hosting.Tests/ProjectResourceTests.cs b/tests/Aspire.Hosting.Tests/ProjectResourceTests.cs index 746612ff819..17fb959465d 100644 --- a/tests/Aspire.Hosting.Tests/ProjectResourceTests.cs +++ b/tests/Aspire.Hosting.Tests/ProjectResourceTests.cs @@ -6,6 +6,7 @@ using Aspire.Hosting.Tests.Helpers; using Aspire.Hosting.Tests.Utils; using Aspire.Hosting.Utils; +using Microsoft.AspNetCore.InternalTesting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Xunit; @@ -17,7 +18,7 @@ public class ProjectResourceTests [Fact] public async Task AddProjectWithInvalidLaunchSettingsShouldThrowSpecificError() { - var projectDetails = await PrepareProjectWithMalformedLaunchSettingsAsync(); + var projectDetails = await PrepareProjectWithMalformedLaunchSettingsAsync().DefaultTimeout(); var ex = Assert.Throws(() => { @@ -46,10 +47,10 @@ public async Task AddProjectWithInvalidLaunchSettingsShouldThrowSpecificError() var launchSettingsFilePath = Path.Combine(propertiesDirectoryPath, "launchSettings.json"); Directory.CreateDirectory(projectDirectoryPath); - await File.WriteAllTextAsync(projectFilePath, csProjContent); + await File.WriteAllTextAsync(projectFilePath, csProjContent).DefaultTimeout(); Directory.CreateDirectory(propertiesDirectoryPath); - await File.WriteAllTextAsync(launchSettingsFilePath, launchSettingsContent); + await File.WriteAllTextAsync(launchSettingsFilePath, launchSettingsContent).DefaultTimeout(); return (projectFilePath, launchSettingsFilePath); } @@ -74,7 +75,7 @@ public async Task AddProjectAddsEnvironmentVariablesAndServiceMetadata() var serviceMetadata = Assert.Single(resource.Annotations.OfType()); Assert.IsType(serviceMetadata); - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); Assert.Collection(config, env => @@ -185,7 +186,7 @@ public async Task AddProjectAddsEnvironmentVariablesAndServiceMetadata_OtlpAuthD var resource = Assert.Single(projectResources); Assert.Equal("projectName", resource.Name); - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); if (hasHeader) { @@ -314,7 +315,7 @@ public async Task AspNetCoreUrlsNotInjectedInPublishMode() var resource = Assert.Single(projectResources); - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(resource, DistributedApplicationOperation.Publish); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(resource, DistributedApplicationOperation.Publish).DefaultTimeout(); Assert.False(config.ContainsKey("ASPNETCORE_URLS")); Assert.False(config.ContainsKey("ASPNETCORE_HTTPS_PORT")); @@ -357,7 +358,7 @@ public async Task ExcludeLaunchProfileAddsHttpOrHttpsEndpointAddsToEnv() var resource = Assert.Single(projectResources); - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); Assert.Equal("http://localhost:p0;https://localhost:p1", config["ASPNETCORE_URLS"]); Assert.Equal("5001", config["ASPNETCORE_HTTPS_PORT"]); @@ -379,7 +380,7 @@ public async Task NoEndpointsDoesNotAddAspNetCoreUrls() var resource = Assert.Single(projectResources); - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); Assert.False(config.ContainsKey("ASPNETCORE_URLS")); Assert.False(config.ContainsKey("ASPNETCORE_HTTPS_PORT")); @@ -404,7 +405,7 @@ public async Task ProjectWithLaunchProfileAddsHttpOrHttpsEndpointAddsToEnv() var resource = Assert.Single(projectResources); - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); Assert.Equal("http://localhost:p0", config["ASPNETCORE_URLS"]); Assert.False(config.ContainsKey("ASPNETCORE_HTTPS_PORT")); @@ -431,7 +432,7 @@ public async Task ProjectWithMultipleLaunchProfileAppUrlsGetsAllUrls() var appModel = app.Services.GetRequiredService(); var projectResources = appModel.GetProjectResources(); var resource = Assert.Single(projectResources); - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); Assert.Equal("https://localhost:p2;http://localhost:p0;http://localhost:p1;https://localhost:p3;https://localhost:p4", config["ASPNETCORE_URLS"]); @@ -477,7 +478,7 @@ public async Task VerifyManifest(bool disableForwardedHeaders) var resource = Assert.Single(projectResources); - var manifest = await ManifestUtils.GetManifest(resource); + var manifest = await ManifestUtils.GetManifest(resource).DefaultTimeout(); var fordwardedHeadersEnvVar = disableForwardedHeaders ? "" @@ -527,7 +528,7 @@ public async Task VerifyManifestWithArgs() var resource = Assert.Single(projectResources); - var manifest = await ManifestUtils.GetManifest(resource); + var manifest = await ManifestUtils.GetManifest(resource).DefaultTimeout(); var expectedManifest = $$""" { @@ -583,7 +584,7 @@ public async Task AddProjectWithArgs() using var app = appBuilder.Build(); - var args = await ArgumentEvaluator.GetArgumentListAsync(project.Resource); + var args = await ArgumentEvaluator.GetArgumentListAsync(project.Resource).DefaultTimeout(); Assert.Collection(args, arg => Assert.Equal("arg1", arg), @@ -618,7 +619,7 @@ public async Task AddProjectWithWildcardUrlInLaunchSettings(bool isProxied, stri var resource = Assert.Single(projectResources); - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); var http = resource.GetEndpoint("http"); var https = resource.GetEndpoint("https"); diff --git a/tests/Aspire.Hosting.Tests/PublishAsConnectionStringTests.cs b/tests/Aspire.Hosting.Tests/PublishAsConnectionStringTests.cs index 5f35839e66c..98a37a608fa 100644 --- a/tests/Aspire.Hosting.Tests/PublishAsConnectionStringTests.cs +++ b/tests/Aspire.Hosting.Tests/PublishAsConnectionStringTests.cs @@ -3,6 +3,7 @@ using Xunit; using Aspire.Hosting.Utils; +using Microsoft.AspNetCore.InternalTesting; namespace Aspire.Hosting.Tests; @@ -17,7 +18,7 @@ public async Task PublishAsConnectionStringConfiguresManifestAsParameter() Assert.True(redis.Resource.TryGetLastAnnotation(out _)); - var manifest = await ManifestUtils.GetManifest(redis.Resource); + var manifest = await ManifestUtils.GetManifest(redis.Resource).DefaultTimeout(); var expected = """ diff --git a/tests/Aspire.Hosting.Tests/PublishAsDockerfileTests.cs b/tests/Aspire.Hosting.Tests/PublishAsDockerfileTests.cs index 0c23d689690..309b14d973e 100644 --- a/tests/Aspire.Hosting.Tests/PublishAsDockerfileTests.cs +++ b/tests/Aspire.Hosting.Tests/PublishAsDockerfileTests.cs @@ -3,6 +3,7 @@ using Xunit; using Aspire.Hosting.Utils; +using Microsoft.AspNetCore.InternalTesting; namespace Aspire.Hosting.Tests; @@ -18,7 +19,7 @@ public async Task PublishAsDockerFileConfiguresManifestWithoutBuildArgs() Assert.True(frontend.Resource.TryGetLastAnnotation(out _)); - var manifest = await ManifestUtils.GetManifest(frontend.Resource); + var manifest = await ManifestUtils.GetManifest(frontend.Resource).DefaultTimeout(); var expected = $$""" @@ -53,7 +54,7 @@ public async Task PublishAsDockerFileConfiguresManifestWithBuildArgs() Assert.True(frontend.Resource.TryGetLastAnnotation(out _)); - var manifest = await ManifestUtils.GetManifest(frontend.Resource); + var manifest = await ManifestUtils.GetManifest(frontend.Resource).DefaultTimeout(); var expected = $$""" @@ -91,7 +92,7 @@ public async Task PublishAsDockerFileConfiguresManifestWithBuildArgsThatHaveNoVa Assert.True(frontend.Resource.TryGetLastAnnotation(out _)); - var manifest = await ManifestUtils.GetManifest(frontend.Resource); + var manifest = await ManifestUtils.GetManifest(frontend.Resource).DefaultTimeout(); var expected = $$""" diff --git a/tests/Aspire.Hosting.Tests/ResourceExtensionsTests.cs b/tests/Aspire.Hosting.Tests/ResourceExtensionsTests.cs index 2be8721d3a2..e65d79d9cc1 100644 --- a/tests/Aspire.Hosting.Tests/ResourceExtensionsTests.cs +++ b/tests/Aspire.Hosting.Tests/ResourceExtensionsTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Hosting.Utils; +using Microsoft.AspNetCore.InternalTesting; using Xunit; namespace Aspire.Hosting.Tests; @@ -98,7 +99,7 @@ public async Task GetEnvironmentVariableValuesAsyncReturnCorrectVariablesInRunMo context.EnvironmentVariables["ELASTIC_PASSWORD"] = "p@ssw0rd1"; }); - var env = await container.Resource.GetEnvironmentVariableValuesAsync(); + var env = await container.Resource.GetEnvironmentVariableValuesAsync().DefaultTimeout(); Assert.Collection(env, env => @@ -131,7 +132,7 @@ public async Task GetEnvironmentVariableValuesAsyncReturnCorrectVariablesUsingVa .WithEnvironment("xpack.security.enabled", "true") .WithEnvironment("ELASTIC_PASSWORD", passwordParameter); - var env = await container.Resource.GetEnvironmentVariableValuesAsync(); + var env = await container.Resource.GetEnvironmentVariableValuesAsync().DefaultTimeout(); Assert.Collection(env, env => @@ -164,7 +165,7 @@ public async Task GetEnvironmentVariableValuesAsyncReturnCorrectVariablesUsingMa .WithEnvironment("xpack.security.enabled", "true") .WithEnvironment("ELASTIC_PASSWORD", passwordParameter); - var env = await container.Resource.GetEnvironmentVariableValuesAsync(DistributedApplicationOperation.Publish); + var env = await container.Resource.GetEnvironmentVariableValuesAsync(DistributedApplicationOperation.Publish).DefaultTimeout(); Assert.Collection(env, env => diff --git a/tests/Aspire.Hosting.Tests/ResourceLoggerServiceTests.cs b/tests/Aspire.Hosting.Tests/ResourceLoggerServiceTests.cs index 49bca79b0e9..110de733e7c 100644 --- a/tests/Aspire.Hosting.Tests/ResourceLoggerServiceTests.cs +++ b/tests/Aspire.Hosting.Tests/ResourceLoggerServiceTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Hosting.Tests.Utils; +using Microsoft.AspNetCore.InternalTesting; using Microsoft.Extensions.Logging; using Xunit; @@ -22,14 +23,14 @@ public async Task AddingResourceLoggerAnnotationAllowsLogging() var logsLoop = ConsoleLoggingTestHelpers.WatchForLogsAsync(logsEnumerator1, 2); // Wait for subscriber to be added - await subsLoop.WaitAsync(TimeSpan.FromSeconds(15)); + await subsLoop.DefaultTimeout(); // Log logger.LogInformation("Hello, world!"); logger.LogError("Hello, error!"); // Wait for logs to be read - var allLogs = await logsLoop.WaitAsync(TimeSpan.FromSeconds(15)); + var allLogs = await logsLoop.DefaultTimeout(); Assert.Equal("2000-12-29T20:59:59.0000000Z Hello, world!", allLogs[0].Content); Assert.False(allLogs[0].IsErrorMessage); @@ -41,15 +42,15 @@ public async Task AddingResourceLoggerAnnotationAllowsLogging() subsLoop = WatchForSubscribers(service); var logsEnumerator2 = service.WatchAsync(testResource).GetAsyncEnumerator(); logsLoop = ConsoleLoggingTestHelpers.WatchForLogsAsync(logsEnumerator2, 2); - await subsLoop.WaitAsync(TimeSpan.FromSeconds(150)); - allLogs = await logsLoop.WaitAsync(TimeSpan.FromSeconds(15)); + await subsLoop.DefaultTimeout(); + allLogs = await logsLoop.DefaultTimeout(); Assert.Equal(2, allLogs.Count); Assert.Equal("2000-12-29T20:59:59.0000000Z Hello, world!", allLogs[0].Content); Assert.Equal("2000-12-29T20:59:59.0000000Z Hello, error!", allLogs[1].Content); - await logsEnumerator1.DisposeAsync(); - await logsEnumerator2.DisposeAsync(); + await logsEnumerator1.DisposeAsync().DefaultTimeout(); + await logsEnumerator2.DisposeAsync().DefaultTimeout(); } [Fact] @@ -63,7 +64,7 @@ public async Task StreamingLogsCancelledAfterComplete() var logsLoop = ConsoleLoggingTestHelpers.WatchForLogsAsync(service, 2, testResource); // Wait for subscriber to be added - await subsLoop.WaitAsync(TimeSpan.FromSeconds(15)); + await subsLoop.DefaultTimeout(); logger.LogInformation("Hello, world!"); logger.LogError("Hello, error!"); @@ -73,7 +74,7 @@ public async Task StreamingLogsCancelledAfterComplete() logger.LogInformation("The third log"); // Wait for logs to be read - var allLogs = await logsLoop.WaitAsync(TimeSpan.FromSeconds(15)); + var allLogs = await logsLoop.DefaultTimeout(); Assert.Collection(allLogs, l => Assert.Equal("2000-12-29T20:59:59.0000000Z Hello, world!", l.Content), @@ -84,7 +85,7 @@ public async Task StreamingLogsCancelledAfterComplete() // New sub should replay logs again. logsLoop = ConsoleLoggingTestHelpers.WatchForLogsAsync(service, 100, testResource); - allLogs = await logsLoop.WaitAsync(TimeSpan.FromSeconds(15)); + allLogs = await logsLoop.DefaultTimeout(); Assert.Collection(allLogs, l => Assert.Equal("2000-12-29T20:59:59.0000000Z Hello, world!", l.Content), @@ -103,14 +104,14 @@ public async Task SecondSubscriberGetsBacklog() var logsLoop = ConsoleLoggingTestHelpers.WatchForLogsAsync(logsEnumerator1, 2); // Wait for subscriber to be added - await subsLoop.WaitAsync(TimeSpan.FromSeconds(15)); + await subsLoop.DefaultTimeout(); // Log logger.LogInformation("Hello, world!"); logger.LogError("Hello, error!"); // Wait for logs to be read - var allLogs = await logsLoop.WaitAsync(TimeSpan.FromSeconds(15)); + var allLogs = await logsLoop.DefaultTimeout(); Assert.Equal("2000-12-29T20:59:59.0000000Z Hello, world!", allLogs[0].Content); Assert.False(allLogs[0].IsErrorMessage); @@ -122,8 +123,8 @@ public async Task SecondSubscriberGetsBacklog() subsLoop = WatchForSubscribers(service); var logsEnumerator2 = service.WatchAsync(testResource).GetAsyncEnumerator(); logsLoop = ConsoleLoggingTestHelpers.WatchForLogsAsync(logsEnumerator2, 2); - await subsLoop.WaitAsync(TimeSpan.FromSeconds(15)); - allLogs = await logsLoop.WaitAsync(TimeSpan.FromSeconds(15)); + await subsLoop.DefaultTimeout(); + allLogs = await logsLoop.DefaultTimeout(); Assert.Equal(2, allLogs.Count); Assert.Equal("2000-12-29T20:59:59.0000000Z Hello, world!", allLogs[0].Content); @@ -135,9 +136,9 @@ public async Task SecondSubscriberGetsBacklog() subsLoop = WatchForSubscribers(service); var logsEnumerator3 = service.WatchAsync(testResource).GetAsyncEnumerator(); logsLoop = ConsoleLoggingTestHelpers.WatchForLogsAsync(logsEnumerator3, 1); - await subsLoop.WaitAsync(TimeSpan.FromSeconds(15)); + await subsLoop.DefaultTimeout(); logger.LogInformation("The third log"); - allLogs = await logsLoop.WaitAsync(TimeSpan.FromSeconds(15)); + allLogs = await logsLoop.DefaultTimeout(); // The backlog should be cleared so only new logs are received Assert.Single(allLogs); @@ -159,10 +160,10 @@ public async Task InMemoryLogsPreservedBetweenWatches() var logsLoop = ConsoleLoggingTestHelpers.WatchForLogsAsync(logsEnumerator1, 1); // Wait for subscriber to be added - await subsLoop.WaitAsync(TimeSpan.FromSeconds(15)); + await subsLoop.DefaultTimeout(); // Read before watching log - var allLogs = await logsLoop.WaitAsync(TimeSpan.FromSeconds(15)); + var allLogs = await logsLoop.DefaultTimeout(); Assert.Equal("2000-12-29T20:59:59.0000000Z Before watching!", allLogs[0].Content); Assert.False(allLogs[0].IsErrorMessage); @@ -171,7 +172,7 @@ public async Task InMemoryLogsPreservedBetweenWatches() logger.LogInformation("While watching!"); logsLoop = ConsoleLoggingTestHelpers.WatchForLogsAsync(logsEnumerator1, 1); - allLogs = await logsLoop.WaitAsync(TimeSpan.FromSeconds(15)); + allLogs = await logsLoop.DefaultTimeout(); Assert.Equal("2000-12-29T20:59:59.0000000Z While watching!", allLogs[0].Content); Assert.False(allLogs[0].IsErrorMessage); @@ -180,15 +181,15 @@ public async Task InMemoryLogsPreservedBetweenWatches() subsLoop = WatchForSubscribers(service); var logsEnumerator2 = service.WatchAsync(testResource).GetAsyncEnumerator(); logsLoop = ConsoleLoggingTestHelpers.WatchForLogsAsync(logsEnumerator2, 2); - await subsLoop.WaitAsync(TimeSpan.FromSeconds(15)); - allLogs = await logsLoop.WaitAsync(TimeSpan.FromSeconds(15)); + await subsLoop.DefaultTimeout(); + allLogs = await logsLoop.DefaultTimeout(); Assert.Equal(2, allLogs.Count); Assert.Equal("2000-12-29T20:59:59.0000000Z Before watching!", allLogs[0].Content); Assert.Equal("2000-12-29T20:59:59.0000000Z While watching!", allLogs[1].Content); - await logsEnumerator1.DisposeAsync(); - await logsEnumerator2.DisposeAsync(); + await logsEnumerator1.DisposeAsync().DefaultTimeout(); + await logsEnumerator2.DisposeAsync().DefaultTimeout(); logger.LogInformation("After watching!"); @@ -198,9 +199,9 @@ public async Task InMemoryLogsPreservedBetweenWatches() subsLoop = WatchForSubscribers(service); var logsEnumerator3 = service.WatchAsync(testResource).GetAsyncEnumerator(); logsLoop = ConsoleLoggingTestHelpers.WatchForLogsAsync(logsEnumerator3, 4); - await subsLoop.WaitAsync(TimeSpan.FromSeconds(15)); + await subsLoop.DefaultTimeout(); logger.LogInformation("While watching again!"); - allLogs = await logsLoop.WaitAsync(TimeSpan.FromSeconds(15)); + allLogs = await logsLoop.DefaultTimeout(); Assert.Equal(4, allLogs.Count); Assert.Equal("2000-12-29T20:59:59.0000000Z Before watching!", allLogs[0].Content); @@ -224,7 +225,7 @@ public async Task MultipleInstancesLogsToAll() var logsLoop = ConsoleLoggingTestHelpers.WatchForLogsAsync(logsEnumerator, 4); // Wait for subscriber to be added - await subsLoop.WaitAsync(TimeSpan.FromSeconds(15)); + await subsLoop.DefaultTimeout(); // Log logger.LogInformation("Hello, world!"); @@ -234,7 +235,7 @@ public async Task MultipleInstancesLogsToAll() Assert.True(service.Loggers.ContainsKey("instance1")); // Wait for logs to be read - var allLogs = await logsLoop.WaitAsync(TimeSpan.FromSeconds(15)); + var allLogs = await logsLoop.DefaultTimeout(); var sortedLogs = allLogs.OrderBy(l => l.LineNumber).ToList(); @@ -245,9 +246,9 @@ public async Task MultipleInstancesLogsToAll() service.Complete(testResource); - Assert.False(await logsEnumerator.MoveNextAsync()); + Assert.False(await logsEnumerator.MoveNextAsync().DefaultTimeout()); - await logsEnumerator.DisposeAsync(); + await logsEnumerator.DisposeAsync().DefaultTimeout(); } private sealed class TestResource(string name) : Resource(name) diff --git a/tests/Aspire.Hosting.Tests/ResourceNotificationTests.cs b/tests/Aspire.Hosting.Tests/ResourceNotificationTests.cs index 36919ad875c..3974f9df60f 100644 --- a/tests/Aspire.Hosting.Tests/ResourceNotificationTests.cs +++ b/tests/Aspire.Hosting.Tests/ResourceNotificationTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Hosting.Tests.Utils; +using Microsoft.AspNetCore.InternalTesting; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Testing; @@ -64,14 +65,14 @@ async Task> GetValuesAsync(CancellationToken cancellationTok return values; } - using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + using var cts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(); var enumerableTask = GetValuesAsync(cts.Token); - await notificationService.PublishUpdateAsync(resource, state => state with { Properties = state.Properties.Add(new("A", "value")) }); + await notificationService.PublishUpdateAsync(resource, state => state with { Properties = state.Properties.Add(new("A", "value")) }).DefaultTimeout(); - await notificationService.PublishUpdateAsync(resource, state => state with { Properties = state.Properties.Add(new("B", "value")) }); + await notificationService.PublishUpdateAsync(resource, state => state with { Properties = state.Properties.Add(new("B", "value")) }).DefaultTimeout(); - var values = await enumerableTask; + var values = await enumerableTask.DefaultTimeout(); Assert.Collection(values, c => @@ -117,16 +118,16 @@ async Task> GetValuesAsync(CancellationToken cancellation) return values; } - using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + using var cts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(); var enumerableTask = GetValuesAsync(cts.Token); - await notificationService.PublishUpdateAsync(resource1, state => state with { Properties = state.Properties.Add(new("A", "value")) }); + await notificationService.PublishUpdateAsync(resource1, state => state with { Properties = state.Properties.Add(new("A", "value")) }).DefaultTimeout(); - await notificationService.PublishUpdateAsync(resource2, state => state with { Properties = state.Properties.Add(new("B", "value")) }); + await notificationService.PublishUpdateAsync(resource2, state => state with { Properties = state.Properties.Add(new("B", "value")) }).DefaultTimeout(); - await notificationService.PublishUpdateAsync(resource1, "replica1", state => state with { Properties = state.Properties.Add(new("C", "value")) }); + await notificationService.PublishUpdateAsync(resource1, "replica1", state => state with { Properties = state.Properties.Add(new("C", "value")) }).DefaultTimeout(); - var values = await enumerableTask; + var values = await enumerableTask.DefaultTimeout(); Assert.Collection(values, c => @@ -159,11 +160,10 @@ public async Task WaitingOnResourceReturnsWhenResourceReachesTargetState() var notificationService = ResourceNotificationServiceTestHelpers.Create(); - using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); - var waitTask = notificationService.WaitForResourceAsync("myResource1", "SomeState", cts.Token); + var waitTask = notificationService.WaitForResourceAsync("myResource1", "SomeState"); - await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = "SomeState" }); - await waitTask; + await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = "SomeState" }).DefaultTimeout(); + await waitTask.DefaultTimeout(); Assert.True(waitTask.IsCompletedSuccessfully); } @@ -175,11 +175,11 @@ public async Task WaitingOnResourceReturnsWhenResourceReachesTargetStateWithDiff var notificationService = ResourceNotificationServiceTestHelpers.Create(); - using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + using var cts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(); var waitTask = notificationService.WaitForResourceAsync("MYreSouRCe1", "sOmeSTAtE", cts.Token); - await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = "SomeState" }); - await waitTask; + await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = "SomeState" }).DefaultTimeout(); + await waitTask.DefaultTimeout(); Assert.True(waitTask.IsCompletedSuccessfully); } @@ -192,10 +192,9 @@ public async Task WaitingOnResourceReturnsImmediatelyWhenResourceIsInTargetState var notificationService = ResourceNotificationServiceTestHelpers.Create(); // Publish the state update first - await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = "SomeState" }); + await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = "SomeState" }).DefaultTimeout(); - using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); - var waitTask = notificationService.WaitForResourceAsync("myResource1", "SomeState", cts.Token); + var waitTask = notificationService.WaitForResourceAsync("myResource1", "SomeState"); Assert.True(waitTask.IsCompletedSuccessfully); } @@ -207,11 +206,10 @@ public async Task WaitingOnResourceReturnsWhenResourceReachesRunningStateIfNoTar var notificationService = ResourceNotificationServiceTestHelpers.Create(); - using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); - var waitTask = notificationService.WaitForResourceAsync("myResource1", targetState: null, cancellationToken: cts.Token); + var waitTask = notificationService.WaitForResourceAsync("myResource1", targetState: null); - await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = KnownResourceStates.Running }); - await waitTask; + await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = KnownResourceStates.Running }).DefaultTimeout(); + await waitTask.DefaultTimeout(); Assert.True(waitTask.IsCompletedSuccessfully); } @@ -223,11 +221,10 @@ public async Task WaitingOnResourceReturnsCorrectStateWhenResourceReachesOneOfTa var notificationService = ResourceNotificationServiceTestHelpers.Create(); - using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); - var waitTask = notificationService.WaitForResourceAsync("myResource1", ["SomeState", "SomeOtherState"], cts.Token); + var waitTask = notificationService.WaitForResourceAsync("myResource1", ["SomeState", "SomeOtherState"]); - await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = "SomeOtherState" }); - var reachedState = await waitTask; + await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = "SomeOtherState" }).DefaultTimeout(); + var reachedState = await waitTask.DefaultTimeout(); Assert.Equal("SomeOtherState", reachedState); } @@ -241,8 +238,8 @@ public async Task WaitingOnResourceReturnsCorrectStateWhenResourceReachesOneOfTa var waitTask = notificationService.WaitForResourceAsync("myResource1", ["SomeState", "SomeOtherState"], default); - await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = "SomeOtherState" }); - var reachedState = await waitTask; + await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = "SomeOtherState" }).DefaultTimeout(); + var reachedState = await waitTask.DefaultTimeout(); Assert.Equal("SomeOtherState", reachedState); } @@ -260,7 +257,7 @@ public async Task WaitingOnResourceThrowsOperationCanceledExceptionIfResourceDoe await Assert.ThrowsAsync(async () => { await waitTask; - }); + }).DefaultTimeout(); } [Fact] @@ -275,7 +272,7 @@ public async Task WaitingOnResourceThrowsOperationCanceledExceptionIfResourceDoe await Assert.ThrowsAsync(async () => { await waitTask; - }); + }).DefaultTimeout(); } [Fact] @@ -292,7 +289,7 @@ public async Task WaitingOnResourceThrowsOperationCanceledExceptionIfResourceDoe await Assert.ThrowsAsync(async () => { await waitTask; - }); + }).DefaultTimeout(); } [Fact] @@ -302,7 +299,7 @@ public async Task PublishLogsStateTextChangesCorrectly() var logger = new FakeLogger(); var notificationService = ResourceNotificationServiceTestHelpers.Create(logger: logger); - await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = "SomeState" }); + await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = "SomeState" }).DefaultTimeout(); var logs = logger.Collector.GetSnapshot(); @@ -313,7 +310,7 @@ public async Task PublishLogsStateTextChangesCorrectly() logger.Collector.Clear(); // Same state text as previous state, no log - await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = "SomeState" }); + await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = "SomeState" }).DefaultTimeout(); logs = logger.Collector.GetSnapshot(); @@ -323,7 +320,7 @@ public async Task PublishLogsStateTextChangesCorrectly() logger.Collector.Clear(); // Different state text, log the transition from the previous state to the new state - await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = "NewState" }); + await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = "NewState" }).DefaultTimeout(); logs = logger.Collector.GetSnapshot(); @@ -333,7 +330,7 @@ public async Task PublishLogsStateTextChangesCorrectly() logger.Collector.Clear(); // Null state text, no log - await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = null }); + await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = null }).DefaultTimeout(); logs = logger.Collector.GetSnapshot(); @@ -343,7 +340,7 @@ public async Task PublishLogsStateTextChangesCorrectly() logger.Collector.Clear(); // Empty state text, no log - await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = "" }); + await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = "" }).DefaultTimeout(); logs = logger.Collector.GetSnapshot(); @@ -353,7 +350,7 @@ public async Task PublishLogsStateTextChangesCorrectly() logger.Collector.Clear(); // White space state text, no log - await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = " " }); + await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = " " }).DefaultTimeout(); logs = logger.Collector.GetSnapshot(); @@ -371,9 +368,9 @@ public async Task PublishLogsTraceStateDetailsCorrectly() var notificationService = ResourceNotificationServiceTestHelpers.Create(logger: logger); var createdDate = DateTime.Now; - await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { CreationTimeStamp = createdDate }); - await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = "SomeState" }); - await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { ExitCode = 0 }); + await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { CreationTimeStamp = createdDate }).DefaultTimeout(); + await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { State = "SomeState" }).DefaultTimeout(); + await notificationService.PublishUpdateAsync(resource1, snapshot => snapshot with { ExitCode = 0 }).DefaultTimeout(); var logs = logger.Collector.GetSnapshot(); diff --git a/tests/Aspire.Hosting.Tests/SlimTestProgramTests.cs b/tests/Aspire.Hosting.Tests/SlimTestProgramTests.cs index b48ddf65d08..e71389eecf0 100644 --- a/tests/Aspire.Hosting.Tests/SlimTestProgramTests.cs +++ b/tests/Aspire.Hosting.Tests/SlimTestProgramTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Hosting.Testing; +using Microsoft.AspNetCore.InternalTesting; using Xunit; namespace Aspire.Hosting.Tests; @@ -21,7 +22,7 @@ public async Task TestProjectStartsAndStopsCleanly() { var testProgram = _slimTestProgramFixture.TestProgram; - using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1)); + using var cts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(TestConstants.LongTimeoutDuration); // Make sure each service is running await EnsureServicesAreRunning(testProgram, cts.Token); @@ -45,7 +46,7 @@ public async Task TestPortOnEndpointAnnotationAndAllocatedEndpointAnnotationMatc { var testProgram = _slimTestProgramFixture.TestProgram; - using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1)); + using var cts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(TestConstants.LongTimeoutDuration); // Make sure each service is running await EnsureServicesAreRunning(testProgram, cts.Token); @@ -63,7 +64,7 @@ public async Task TestPortOnEndpointAnnotationAndAllocatedEndpointAnnotationMatc { var testProgram = _slimTestProgramFixture.TestProgram; - using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1)); + using var cts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(TestConstants.LongTimeoutDuration); // Make sure each service is running await EnsureServicesAreRunning(testProgram, cts.Token); diff --git a/tests/Aspire.Hosting.Tests/TestProgramFixture.cs b/tests/Aspire.Hosting.Tests/TestProgramFixture.cs index ecf7a4ef70a..ddf13ad0afb 100644 --- a/tests/Aspire.Hosting.Tests/TestProgramFixture.cs +++ b/tests/Aspire.Hosting.Tests/TestProgramFixture.cs @@ -3,6 +3,7 @@ using Aspire.Hosting.Testing; using Aspire.Hosting.Tests.Utils; +using Microsoft.AspNetCore.InternalTesting; using Xunit; namespace Aspire.Hosting.Tests; @@ -29,7 +30,7 @@ public async Task InitializeAsync() _app = _testProgram.Build(); - using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(5)); + using var cts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(TestConstants.LongTimeoutDuration); await _app.StartAsync(cts.Token); diff --git a/tests/Aspire.Hosting.Tests/Utils/TestDistributedApplicationBuilder.cs b/tests/Aspire.Hosting.Tests/Utils/TestDistributedApplicationBuilder.cs index aed5c6891f8..cd341c48f10 100644 --- a/tests/Aspire.Hosting.Tests/Utils/TestDistributedApplicationBuilder.cs +++ b/tests/Aspire.Hosting.Tests/Utils/TestDistributedApplicationBuilder.cs @@ -62,7 +62,7 @@ public static TestDistributedApplicationBuilder Create(Action - Create(o => o.ContainerRegistryOverride = TestConstants.AspireTestContainerRegistry, testOutputHelper); + Create(o => o.ContainerRegistryOverride = ComponentTestConstants.AspireTestContainerRegistry, testOutputHelper); private TestDistributedApplicationBuilder(Action? configureOptions, ITestOutputHelper? testOutputHelper = null) { diff --git a/tests/Aspire.Hosting.Tests/WaitForTests.cs b/tests/Aspire.Hosting.Tests/WaitForTests.cs index 7d4342283a7..b5319459ddf 100644 --- a/tests/Aspire.Hosting.Tests/WaitForTests.cs +++ b/tests/Aspire.Hosting.Tests/WaitForTests.cs @@ -3,6 +3,7 @@ using Aspire.Components.Common.Tests; using Aspire.Hosting.Utils; +using Microsoft.AspNetCore.InternalTesting; using Microsoft.Extensions.DependencyInjection; using Xunit; using Xunit.Abstractions; @@ -23,7 +24,7 @@ public async Task ResourceThatFailsToStartDueToExceptionDoesNotCauseStartAsyncTo var dependingExecutableResource = builder.AddExecutable("dependingexecutableresource", "doesnotmatter", "alsodoesntmatter") .WaitFor(throwingResource); - var abortCts = new CancellationTokenSource(TimeSpan.FromSeconds(60)); + var abortCts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(TestConstants.LongTimeoutDuration); using var app = builder.Build(); await app.StartAsync(abortCts.Token); @@ -95,13 +96,13 @@ public async Task EnsureDependentResourceMovesIntoWaitingState() // into a Running state, so rather than awaiting it we'll hold onto the // task so we can inspect the state of the Nginx resource which should // be in a waiting state if everything is working correctly. - var startupCts = new CancellationTokenSource(TimeSpan.FromSeconds(60)); + var startupCts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(TestConstants.LongTimeoutDuration); var startTask = app.StartAsync(startupCts.Token); // We don't want to wait forever for Nginx to move into a waiting state, - // it should be super quick, but we'll allow 60 seconds just in case the + // it should be super quick, but we'll allow a long timeout just in case the // CI machine is chugging (also useful when collecting code coverage). - var waitingStateCts = new CancellationTokenSource(TimeSpan.FromSeconds(60)); + var waitingStateCts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(TestConstants.LongTimeoutDuration); var rns = app.Services.GetRequiredService(); await rns.WaitForResourceAsync(nginx.Resource.Name, "Waiting", waitingStateCts.Token); @@ -136,13 +137,13 @@ public async Task WaitForCompletionWaitsForTerminalStateOfDependencyResource() // into a Finished state, so rather than awaiting it we'll hold onto the // task so we can inspect the state of the Nginx resource which should // be in a waiting state if everything is working correctly. - var startupCts = new CancellationTokenSource(TimeSpan.FromSeconds(120)); + var startupCts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(TestConstants.LongTimeoutDuration); var startTask = app.StartAsync(startupCts.Token); // We don't want to wait forever for Nginx to move into a waiting state, // it should be super quick, but we'll allow 60 seconds just in case the // CI machine is chugging (also useful when collecting code coverage). - var waitingStateCts = new CancellationTokenSource(TimeSpan.FromSeconds(120)); + var waitingStateCts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(TestConstants.LongTimeoutDuration); var rns = app.Services.GetRequiredService(); await rns.WaitForResourceAsync(nginx.Resource.Name, KnownResourceStates.Waiting, waitingStateCts.Token); @@ -159,7 +160,7 @@ await rns.PublishUpdateAsync(dependency.Resource, s => s with // This time we want to wait for Nginx to move into a Running state to verify that // it successfully started after we moved the dependency resource into the Finished, but // we need to give it more time since we have to download the image in CI. - var runningStateCts = new CancellationTokenSource(TimeSpan.FromSeconds(60)); + var runningStateCts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(TestConstants.LongTimeoutDuration); await rns.WaitForResourceAsync(nginx.Resource.Name, KnownResourceStates.Running, runningStateCts.Token); await startTask; @@ -184,13 +185,13 @@ public async Task WaitForThrowsIfResourceMovesToTerminalStateBeforeRunning() // into a Finished state, so rather than awaiting it we'll hold onto the // task so we can inspect the state of the Nginx resource which should // be in a waiting state if everything is working correctly. - var startupCts = new CancellationTokenSource(TimeSpan.FromSeconds(120)); + var startupCts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(TestConstants.LongTimeoutDuration); var startTask = app.StartAsync(startupCts.Token); // We don't want to wait forever for Nginx to move into a waiting state, // it should be super quick, but we'll allow 60 seconds just in case the // CI machine is chugging (also useful when collecting code coverage). - var waitingStateCts = new CancellationTokenSource(TimeSpan.FromSeconds(120)); + var waitingStateCts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(TestConstants.LongTimeoutDuration); var rns = app.Services.GetRequiredService(); await rns.WaitForResourceAsync(nginx.Resource.Name, "Waiting", waitingStateCts.Token); @@ -207,7 +208,7 @@ await rns.PublishUpdateAsync(dependency.Resource, s => s with // This time we want to wait for Nginx to move into a Running state to verify that // it successfully started after we moved the dependency resource into the Finished, but // we need to give it more time since we have to download the image in CI. - var runningStateCts = new CancellationTokenSource(TimeSpan.FromSeconds(60)); + var runningStateCts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(TestConstants.LongTimeoutDuration); await rns.WaitForResourceAsync(nginx.Resource.Name, KnownResourceStates.FailedToStart, runningStateCts.Token); await startTask; @@ -232,13 +233,13 @@ public async Task EnsureDependencyResourceThatReturnsNonMatchingExitCodeResultsI // into a Finished state, so rather than awaiting it we'll hold onto the // task so we can inspect the state of the Nginx resource which should // be in a waiting state if everything is working correctly. - var startupCts = new CancellationTokenSource(TimeSpan.FromSeconds(60)); + var startupCts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(TestConstants.LongTimeoutDuration); var startTask = app.StartAsync(startupCts.Token); // We don't want to wait forever for Nginx to move into a waiting state, // it should be super quick, but we'll allow 60 seconds just in case the // CI machine is chugging (also useful when collecting code coverage). - var waitingStateCts = new CancellationTokenSource(TimeSpan.FromSeconds(60)); + var waitingStateCts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(TestConstants.LongTimeoutDuration); var rns = app.Services.GetRequiredService(); await rns.WaitForResourceAsync(nginx.Resource.Name, KnownResourceStates.Waiting, waitingStateCts.Token); @@ -254,7 +255,7 @@ await rns.PublishUpdateAsync(dependency.Resource, s => s with // This time we want to wait for Nginx to move into a FailedToStart state to verify that // it didn't start if the dependency resource didn't finish with the correct exit code. - var runningStateCts = new CancellationTokenSource(TimeSpan.FromSeconds(60)); + var runningStateCts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(TestConstants.LongTimeoutDuration); await rns.WaitForResourceAsync(nginx.Resource.Name, KnownResourceStates.FailedToStart, runningStateCts.Token); await startTask; @@ -281,13 +282,13 @@ public async Task DependencyWithGreaterThan1ReplicaAnnotationCausesDependentReso // into a Finished state, so rather than awaiting it we'll hold onto the // task so we can inspect the state of the Nginx resource which should // be in a waiting state if everything is working correctly. - var startupCts = new CancellationTokenSource(TimeSpan.FromSeconds(60)); + var startupCts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(TestConstants.LongTimeoutDuration); var startTask = app.StartAsync(startupCts.Token); // We don't want to wait forever for Nginx to move into a waiting state, // it should be super quick, but we'll allow 60 seconds just in case the // CI machine is chugging (also useful when collecting code coverage). - var waitingStateCts = new CancellationTokenSource(TimeSpan.FromSeconds(60)); + var waitingStateCts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(TestConstants.LongTimeoutDuration); var rns = app.Services.GetRequiredService(); await rns.WaitForResourceAsync(nginx.Resource.Name, "FailedToStart", waitingStateCts.Token); @@ -315,13 +316,13 @@ public async Task WaitForCompletionSucceedsIfDependentResourceEntersTerminalStat // into a Finished state, so rather than awaiting it we'll hold onto the // task so we can inspect the state of the Nginx resource which should // be in a waiting state if everything is working correctly. - var startupCts = new CancellationTokenSource(TimeSpan.FromSeconds(60)); + var startupCts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(TestConstants.LongTimeoutDuration); var startTask = app.StartAsync(startupCts.Token); // We don't want to wait forever for Nginx to move into a waiting state, // it should be super quick, but we'll allow 60 seconds just in case the // CI machine is chugging (also useful when collecting code coverage). - var waitingStateCts = new CancellationTokenSource(TimeSpan.FromSeconds(60)); + var waitingStateCts = AsyncTestHelpers.CreateDefaultTimeoutTokenSource(TestConstants.LongTimeoutDuration); var rns = app.Services.GetRequiredService(); await rns.WaitForResourceAsync(nginx.Resource.Name, KnownResourceStates.Waiting, waitingStateCts.Token); diff --git a/tests/Aspire.Hosting.Tests/WithEndpointTests.cs b/tests/Aspire.Hosting.Tests/WithEndpointTests.cs index bafddc5a019..a03cbce88c9 100644 --- a/tests/Aspire.Hosting.Tests/WithEndpointTests.cs +++ b/tests/Aspire.Hosting.Tests/WithEndpointTests.cs @@ -3,6 +3,7 @@ using Aspire.Hosting.Tests.Utils; using Aspire.Hosting.Utils; +using Microsoft.AspNetCore.InternalTesting; using Microsoft.Extensions.DependencyInjection; using Xunit; @@ -211,7 +212,7 @@ public async Task CanAddEndpointsWithContainerPortAndEnv() var resource = Assert.Single(exeResources); - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); Assert.Equal("foo", resource.Name); var endpoints = resource.Annotations.OfType().ToArray(); @@ -268,7 +269,7 @@ public async Task VerifyManifestWithBothDifferentPortAndTargetPort() var container = builder.AddContainer("app", "image") .WithEndpoint(name: "ep0", port: 8080, targetPort: 3000); - var manifest = await ManifestUtils.GetManifest(container.Resource); + var manifest = await ManifestUtils.GetManifest(container.Resource).DefaultTimeout(); var expectedManifest = """ { @@ -296,7 +297,7 @@ public async Task VerifyManifestWithHttpPortWithTargetPort() var container = builder.AddContainer("app", "image") .WithHttpEndpoint(name: "h1", targetPort: 3001); - var manifest = await ManifestUtils.GetManifest(container.Resource); + var manifest = await ManifestUtils.GetManifest(container.Resource).DefaultTimeout(); var expectedManifest = """ { @@ -323,7 +324,7 @@ public async Task VerifyManifestWithHttpsAndTargetPort() var container = builder.AddContainer("app", "image") .WithHttpsEndpoint(name: "h2", targetPort: 3001); - var manifest = await ManifestUtils.GetManifest(container.Resource); + var manifest = await ManifestUtils.GetManifest(container.Resource).DefaultTimeout(); var expectedManifest = """ { @@ -350,7 +351,7 @@ public async Task VerifyManifestContainerWithHttpEndpointAndNoPortsAllocatesPort var container = builder.AddContainer("app", "image") .WithHttpEndpoint(name: "h3"); - var manifest = await ManifestUtils.GetManifest(container.Resource); + var manifest = await ManifestUtils.GetManifest(container.Resource).DefaultTimeout(); var expectedManifest = """ { @@ -377,7 +378,7 @@ public async Task VerifyManifestContainerWithHttpsEndpointAllocatesPort() var container = builder.AddContainer("app", "image") .WithHttpsEndpoint(name: "h4"); - var manifest = await ManifestUtils.GetManifest(container.Resource); + var manifest = await ManifestUtils.GetManifest(container.Resource).DefaultTimeout(); var expectedManifest = """ { @@ -404,7 +405,7 @@ public async Task VerifyManifestWithHttpEndpointAndPortOnlySetsTargetPort() var container = builder.AddContainer("app", "image") .WithHttpEndpoint(name: "otlp", port: 1004); - var manifest = await ManifestUtils.GetManifest(container.Resource); + var manifest = await ManifestUtils.GetManifest(container.Resource).DefaultTimeout(); var expectedManifest = """ { @@ -431,7 +432,7 @@ public async Task VerifyManifestWithTcpEndpointAndNoPortAllocatesPort() var container = builder.AddContainer("app", "image") .WithEndpoint(name: "custom"); - var manifest = await ManifestUtils.GetManifest(container.Resource); + var manifest = await ManifestUtils.GetManifest(container.Resource).DefaultTimeout(); var expectedManifest = """ { @@ -462,7 +463,7 @@ public async Task VerifyManifestProjectWithDefaultHttpEndpointsDoesNotAllocatePo .WithHttpsEndpoint(name: "hps2") // Will get a targetPort .WithEndpoint(scheme: "tcp", name: "tcp0"); // Will get a targetPort - var manifest = await ManifestUtils.GetManifest(project.Resource); + var manifest = await ManifestUtils.GetManifest(project.Resource).DefaultTimeout(); var expectedManifest = """ @@ -532,7 +533,7 @@ public async Task VerifyManifestProjectWithEndpointsSetsPortsEnvVariables() // Should not be included in HTTP_PORTS .WithEndpointsInEnvironment(e => e.Name != "dontinjectme"); - var manifest = await ManifestUtils.GetManifest(project.Resource); + var manifest = await ManifestUtils.GetManifest(project.Resource).DefaultTimeout(); var expectedEnv = """ @@ -559,7 +560,7 @@ public async Task VerifyManifestPortAllocationIsGlobal() var container1 = builder.AddContainer("app1", "image") .WithEndpoint(name: "custom"); - var manifests = await ManifestUtils.GetManifests([container0.Resource, container1.Resource]); + var manifests = await ManifestUtils.GetManifests([container0.Resource, container1.Resource]).DefaultTimeout(); var expectedManifest0 = """ { diff --git a/tests/Aspire.Hosting.Tests/WithEnvironmentTests.cs b/tests/Aspire.Hosting.Tests/WithEnvironmentTests.cs index ec382850e35..ffe75a19850 100644 --- a/tests/Aspire.Hosting.Tests/WithEnvironmentTests.cs +++ b/tests/Aspire.Hosting.Tests/WithEnvironmentTests.cs @@ -3,6 +3,7 @@ using Aspire.Hosting.Tests.Utils; using Aspire.Hosting.Utils; +using Microsoft.AspNetCore.InternalTesting; using Microsoft.Extensions.DependencyInjection; using Xunit; @@ -29,7 +30,7 @@ public async Task BuiltApplicationHasAccessToIServiceProviderViaEnvironmentCallb var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync( container.Resource, serviceProvider: serviceProvider - ); + ).DefaultTimeout(); Assert.Equal("true", config["SP_AVAILABLE"]); } @@ -49,7 +50,7 @@ public async Task EnvironmentReferencingEndpointPopulatesWithBindingUrl() var projectB = builder.AddProject("projectB") .WithEnvironment("myName", projectA.GetEndpoint("mybinding")); - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); Assert.Equal("https://localhost:2000", config["myName"]); } @@ -62,7 +63,7 @@ public async Task SimpleEnvironmentWithNameAndValue() var project = builder.AddProject("projectA") .WithEnvironment("myName", "value"); - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(project.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(project.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); Assert.Equal("value", config["myName"]); } @@ -78,7 +79,7 @@ public async Task SimpleEnvironmentWithNameAndReferenceExpressionValue() var project = builder.AddProject("projectA") .WithEnvironment("myName", parameterExpression); - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(project.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(project.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); Assert.Equal("value", config["myName"]); } @@ -94,7 +95,7 @@ public async Task EnvironmentCallbackPopulatesValueWhenCalled() environmentValue = "value2"; // Call environment variable callbacks. - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectA.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectA.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); Assert.Equal("value2", config["myName"]); } @@ -111,7 +112,7 @@ public async Task EnvironmentCallbackPopulatesValueWhenParameterResourceProvided var projectA = builder.AddProject("projectA") .WithEnvironment("MY_PARAMETER", parameter); - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectA.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectA.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); Assert.Equal("MY_PARAMETER_VALUE", config["MY_PARAMETER"]); } @@ -127,7 +128,7 @@ public async Task EnvironmentCallbackPopulatesWithExpressionPlaceholderWhenPubli .WithEnvironment("MY_PARAMETER", parameter); var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectA.Resource, - DistributedApplicationOperation.Publish); + DistributedApplicationOperation.Publish).DefaultTimeout(); Assert.Equal("{parameter.value}", config["MY_PARAMETER"]); } @@ -146,7 +147,7 @@ public async Task EnvironmentCallbackThrowsWhenParameterValueMissingInDcpMode() projectA.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance - )); + )).DefaultTimeout(); Assert.Equal("Parameter resource could not be used because configuration key 'Parameters:parameter' is missing and the Parameter has no default value.", exception.Message); } @@ -166,7 +167,7 @@ public async Task ComplexEnvironmentCallbackPopulatesValueWhenCalled() environmentValue = "value2"; // Call environment variable callbacks. - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectA.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectA.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); Assert.Equal("value2", config["myName"]); } @@ -193,8 +194,8 @@ public async Task EnvironmentVariableExpressions() .WithEnvironment("TARGET_PORT", $"{endpoint.Property(EndpointProperty.TargetPort)}") .WithEnvironment("HOST", $"{test.Resource};name=1"); - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(containerB.Resource); - var manifestConfig = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(containerB.Resource, DistributedApplicationOperation.Publish); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(containerB.Resource).DefaultTimeout(); + var manifestConfig = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(containerB.Resource, DistributedApplicationOperation.Publish).DefaultTimeout(); Assert.Equal(4, config.Count); Assert.Equal($"http://container1:10005/foo", config["URL"]); @@ -226,7 +227,7 @@ public async Task EnvironmentVariableWithDynamicTargetPort() var containerB = builder.AddContainer("container2", "imageB") .WithEnvironment("TARGET_PORT", $"{endpoint.Property(EndpointProperty.TargetPort)}"); - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(containerB.Resource); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(containerB.Resource).DefaultTimeout(); var pair = Assert.Single(config); Assert.Equal("TARGET_PORT", pair.Key); @@ -250,13 +251,13 @@ public async Task EnvironmentWithConnectionStringSetsProperEnvironmentVariable() targetBuilder.WithEnvironment(envVarName, sourceBuilder); // Call environment variable callbacks for the Run operation. - var runConfig = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(targetBuilder.Resource, DistributedApplicationOperation.Run); + var runConfig = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(targetBuilder.Resource, DistributedApplicationOperation.Run).DefaultTimeout(); // Assert Assert.Single(runConfig, kvp => kvp.Key == envVarName && kvp.Value == sourceCon); // Call environment variable callbacks for the Publish operation. - var publishConfig = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(targetBuilder.Resource, DistributedApplicationOperation.Publish); + var publishConfig = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(targetBuilder.Resource, DistributedApplicationOperation.Publish).DefaultTimeout(); // Assert Assert.Single(publishConfig, kvp => kvp.Key == envVarName && kvp.Value == "{sourceService.connectionString}"); diff --git a/tests/Aspire.Hosting.Tests/WithReferenceTests.cs b/tests/Aspire.Hosting.Tests/WithReferenceTests.cs index b29e0686b41..6344604cde6 100644 --- a/tests/Aspire.Hosting.Tests/WithReferenceTests.cs +++ b/tests/Aspire.Hosting.Tests/WithReferenceTests.cs @@ -3,6 +3,7 @@ using Aspire.Hosting.Tests.Utils; using Aspire.Hosting.Utils; +using Microsoft.AspNetCore.InternalTesting; using Xunit; namespace Aspire.Hosting.Tests; @@ -25,7 +26,7 @@ public async Task ResourceWithSingleEndpointProducesSimplifiedEnvironmentVariabl var projectB = builder.AddProject("b").WithReference(projectA.GetEndpoint(endpointName)); // Call environment variable callbacks. - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); Assert.Equal("https://localhost:2000", config["services__projecta__mybinding__0"]); } @@ -48,7 +49,7 @@ public async Task ResourceWithConflictingEndpointsProducesFullyScopedEnvironment .WithReference(projectA.GetEndpoint("myconflictingbinding")); // Call environment variable callbacks. - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); Assert.Equal("https://localhost:2000", config["services__projecta__mybinding__0"]); Assert.Equal("https://localhost:3000", config["services__projecta__myconflictingbinding__0"]); @@ -73,7 +74,7 @@ public async Task ResourceWithNonConflictingEndpointsProducesAllVariantsOfEnviro .WithReference(projectA.GetEndpoint("mynonconflictingbinding")); // Call environment variable callbacks. - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); Assert.Equal("https://localhost:2000", config["services__projecta__mybinding__0"]); Assert.Equal("http://localhost:3000", config["services__projecta__mynonconflictingbinding__0"]); @@ -96,7 +97,7 @@ public async Task ResourceWithConflictingEndpointsProducesAllEnvironmentVariable .WithReference(projectA); // Call environment variable callbacks. - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); Assert.Equal("https://localhost:2000", config["services__projecta__mybinding__0"]); Assert.Equal("https://localhost:3000", config["services__projecta__mybinding2__0"]); @@ -117,7 +118,7 @@ public async Task ResourceWithEndpointsProducesAllEnvironmentVariables() var projectB = builder.AddProject("projectb") .WithReference(projectA); // Call environment variable callbacks. - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); Assert.Equal("https://localhost:2000", config["services__projecta__mybinding__0"]); Assert.Equal("http://localhost:3000", config["services__projecta__mybinding2__0"]); @@ -136,7 +137,7 @@ public async Task ConnectionStringResourceThrowsWhenMissingConnectionString() await Assert.ThrowsAsync(async () => { await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); - }); + }).DefaultTimeout(); } [Fact] @@ -149,7 +150,7 @@ public async Task ConnectionStringResourceOptionalWithMissingConnectionString() var projectB = builder.AddProject("projectB") .WithReference(resource, optional: true); - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); var servicesKeysCount = config.Keys.Count(k => k.StartsWith("ConnectionStrings__")); Assert.Equal(0, servicesKeysCount); @@ -169,7 +170,7 @@ public async Task ParameterAsConnectionStringResourceThrowsWhenConnectionStringS var exception = await Assert.ThrowsAsync(async () => { var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); - }); + }).DefaultTimeout(); Assert.Equal("Connection string parameter resource could not be used because connection string 'missingresource' is missing.", exception.Message); } @@ -187,7 +188,7 @@ public async Task ParameterAsConnectionStringResourceInjectsConnectionStringWhen .WithReference(resource); // Call environment variable callbacks. - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); Assert.Equal("test connection string", config["ConnectionStrings__resource"]); } @@ -203,7 +204,7 @@ public async Task ParameterAsConnectionStringResourceInjectsExpressionWhenPublis .WithReference(resource); // Call environment variable callbacks. - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Publish); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Publish).DefaultTimeout(); Assert.Equal("{resource.connectionString}", config["ConnectionStrings__resource"]); } @@ -219,7 +220,7 @@ public async Task ParameterAsConnectionStringResourceInjectsCorrectEnvWhenPublis .WithReference(resource); // Call environment variable callbacks. - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Publish); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Publish).DefaultTimeout(); Assert.Equal("{resource.connectionString}", config["MY_ENV"]); } @@ -238,7 +239,7 @@ public async Task ConnectionStringResourceWithConnectionString() .WithReference(resource); // Call environment variable callbacks. - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); var servicesKeysCount = config.Keys.Count(k => k.StartsWith("ConnectionStrings__")); Assert.Equal(1, servicesKeysCount); @@ -260,7 +261,7 @@ public async Task ConnectionStringResourceWithConnectionStringOverwriteName() .WithReference(resource, connectionName: "bob"); // Call environment variable callbacks. - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectB.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); var servicesKeysCount = config.Keys.Count(k => k.StartsWith("ConnectionStrings__")); Assert.Equal(1, servicesKeysCount); @@ -292,7 +293,7 @@ public async Task WithReferenceHttpProduceEnvironmentVariables() .WithReference("petstore", new Uri("https://petstore.swagger.io/")); // Call environment variable callbacks. - var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectA.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance); + var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(projectA.Resource, DistributedApplicationOperation.Run, TestServiceProvider.Instance).DefaultTimeout(); var servicesKeysCount = config.Keys.Count(k => k.StartsWith("services__")); Assert.Equal(1, servicesKeysCount); diff --git a/tests/Aspire.Milvus.Client.Tests/MilvusContainerFixture.cs b/tests/Aspire.Milvus.Client.Tests/MilvusContainerFixture.cs index eddb69e6daf..a959b874be3 100644 --- a/tests/Aspire.Milvus.Client.Tests/MilvusContainerFixture.cs +++ b/tests/Aspire.Milvus.Client.Tests/MilvusContainerFixture.cs @@ -20,7 +20,7 @@ public async Task InitializeAsync() if (RequiresDockerAttribute.IsSupported) { Container = new MilvusBuilder() - .WithImage($"{TestConstants.AspireTestContainerRegistry}/{MilvusContainerImageTags.Image}:{MilvusContainerImageTags.Tag}") + .WithImage($"{ComponentTestConstants.AspireTestContainerRegistry}/{MilvusContainerImageTags.Image}:{MilvusContainerImageTags.Tag}") .Build(); await Container.StartAsync(); } diff --git a/tests/Aspire.MongoDB.Driver.Tests/MongoDbContainerFixture.cs b/tests/Aspire.MongoDB.Driver.Tests/MongoDbContainerFixture.cs index 95814b50095..44f1ba68f15 100644 --- a/tests/Aspire.MongoDB.Driver.Tests/MongoDbContainerFixture.cs +++ b/tests/Aspire.MongoDB.Driver.Tests/MongoDbContainerFixture.cs @@ -22,7 +22,7 @@ public async Task InitializeAsync() // testcontainers uses mongo:mongo by default, // resetting that for tests Container = new MongoDbBuilder() - .WithImage($"{TestConstants.AspireTestContainerRegistry}/{MongoDBContainerImageTags.Image}:{MongoDBContainerImageTags.Tag}") + .WithImage($"{ComponentTestConstants.AspireTestContainerRegistry}/{MongoDBContainerImageTags.Image}:{MongoDBContainerImageTags.Tag}") .WithUsername(null) .WithPassword(null) .Build(); diff --git a/tests/Aspire.MySqlConnector.Tests/MySqlContainerFixture.cs b/tests/Aspire.MySqlConnector.Tests/MySqlContainerFixture.cs index b521c27a3a7..2f2a9839385 100644 --- a/tests/Aspire.MySqlConnector.Tests/MySqlContainerFixture.cs +++ b/tests/Aspire.MySqlConnector.Tests/MySqlContainerFixture.cs @@ -20,7 +20,7 @@ public async Task InitializeAsync() if (RequiresDockerAttribute.IsSupported) { Container = new MySqlBuilder() - .WithImage($"{TestConstants.AspireTestContainerRegistry}/{MySqlContainerImageTags.Image}:{MySqlContainerImageTags.Tag}") + .WithImage($"{ComponentTestConstants.AspireTestContainerRegistry}/{MySqlContainerImageTags.Image}:{MySqlContainerImageTags.Tag}") .Build(); await Container.StartAsync(); } diff --git a/tests/Aspire.NATS.Net.Tests/NatsContainerFixture.cs b/tests/Aspire.NATS.Net.Tests/NatsContainerFixture.cs index f982c31ff20..6f515e3a932 100644 --- a/tests/Aspire.NATS.Net.Tests/NatsContainerFixture.cs +++ b/tests/Aspire.NATS.Net.Tests/NatsContainerFixture.cs @@ -20,7 +20,7 @@ public async Task InitializeAsync() if (RequiresDockerAttribute.IsSupported) { Container = new NatsBuilder() - .WithImage($"{TestConstants.AspireTestContainerRegistry}/{NatsContainerImageTags.Image}:{NatsContainerImageTags.Tag}") + .WithImage($"{ComponentTestConstants.AspireTestContainerRegistry}/{NatsContainerImageTags.Image}:{NatsContainerImageTags.Tag}") .Build(); await Container.StartAsync(); } diff --git a/tests/Aspire.Npgsql.Tests/PostgreSQLContainerFixture.cs b/tests/Aspire.Npgsql.Tests/PostgreSQLContainerFixture.cs index 5f5f8abeefc..f5ee028b4d0 100644 --- a/tests/Aspire.Npgsql.Tests/PostgreSQLContainerFixture.cs +++ b/tests/Aspire.Npgsql.Tests/PostgreSQLContainerFixture.cs @@ -20,7 +20,7 @@ public async Task InitializeAsync() if (RequiresDockerAttribute.IsSupported) { Container = new PostgreSqlBuilder() - .WithImage($"{TestConstants.AspireTestContainerRegistry}/{PostgresContainerImageTags.Image}:{PostgresContainerImageTags.Tag}") + .WithImage($"{ComponentTestConstants.AspireTestContainerRegistry}/{PostgresContainerImageTags.Image}:{PostgresContainerImageTags.Tag}") .Build(); await Container.StartAsync(); } diff --git a/tests/Aspire.Oracle.EntityFrameworkCore.Tests/OracleContainerFixture.cs b/tests/Aspire.Oracle.EntityFrameworkCore.Tests/OracleContainerFixture.cs index ee0a328b47a..7c119d63d68 100644 --- a/tests/Aspire.Oracle.EntityFrameworkCore.Tests/OracleContainerFixture.cs +++ b/tests/Aspire.Oracle.EntityFrameworkCore.Tests/OracleContainerFixture.cs @@ -30,7 +30,7 @@ public async Task InitializeAsync() Container = new OracleBuilder() .WithPortBinding(1521, true) .WithHostname("localhost") - .WithImage($"{TestConstants.AspireTestContainerRegistry}/gvenzl/oracle-xe:21.3.0-slim-faststart") + .WithImage($"{ComponentTestConstants.AspireTestContainerRegistry}/gvenzl/oracle-xe:21.3.0-slim-faststart") .WithWaitStrategy(Wait .ForUnixContainer() .UntilMessageIsLogged("Completed: ALTER DATABASE OPEN") diff --git a/tests/Aspire.RabbitMQ.Client.Tests/AspireRabbitMQLoggingTests.cs b/tests/Aspire.RabbitMQ.Client.Tests/AspireRabbitMQLoggingTests.cs index 1ca8d40c5e0..ca6bfc0b344 100644 --- a/tests/Aspire.RabbitMQ.Client.Tests/AspireRabbitMQLoggingTests.cs +++ b/tests/Aspire.RabbitMQ.Client.Tests/AspireRabbitMQLoggingTests.cs @@ -29,7 +29,7 @@ public class AspireRabbitMQLoggingTests public async Task EndToEndLoggingTest() { await using var rabbitMqContainer = new RabbitMqBuilder() - .WithImage($"{TestConstants.AspireTestContainerRegistry}/{RabbitMQContainerImageTags.Image}:{RabbitMQContainerImageTags.Tag}") + .WithImage($"{ComponentTestConstants.AspireTestContainerRegistry}/{RabbitMQContainerImageTags.Image}:{RabbitMQContainerImageTags.Tag}") .Build(); await rabbitMqContainer.StartAsync(); diff --git a/tests/Aspire.RabbitMQ.Client.Tests/RabbitMQContainerFixture.cs b/tests/Aspire.RabbitMQ.Client.Tests/RabbitMQContainerFixture.cs index 334eeef9c5a..54c76d51777 100644 --- a/tests/Aspire.RabbitMQ.Client.Tests/RabbitMQContainerFixture.cs +++ b/tests/Aspire.RabbitMQ.Client.Tests/RabbitMQContainerFixture.cs @@ -34,7 +34,7 @@ public async Task DisposeAsync() public static async Task CreateContainerAsync() { var container = new RabbitMqBuilder() - .WithImage($"{TestConstants.AspireTestContainerRegistry}/{RabbitMQContainerImageTags.Image}:{RabbitMQContainerImageTags.Tag}") + .WithImage($"{ComponentTestConstants.AspireTestContainerRegistry}/{RabbitMQContainerImageTags.Image}:{RabbitMQContainerImageTags.Tag}") .Build(); await container.StartAsync(); diff --git a/tests/Aspire.StackExchange.Redis.Tests/RedisContainerFixture.cs b/tests/Aspire.StackExchange.Redis.Tests/RedisContainerFixture.cs index b831af6cd7b..9ef1f1f6a89 100644 --- a/tests/Aspire.StackExchange.Redis.Tests/RedisContainerFixture.cs +++ b/tests/Aspire.StackExchange.Redis.Tests/RedisContainerFixture.cs @@ -34,7 +34,7 @@ public async Task DisposeAsync() public static async Task CreateContainerAsync() { var container = new RedisBuilder() - .WithImage($"{TestConstants.AspireTestContainerRegistry}/{RedisContainerImageTags.Image}:{RedisContainerImageTags.Tag}") + .WithImage($"{ComponentTestConstants.AspireTestContainerRegistry}/{RedisContainerImageTags.Image}:{RedisContainerImageTags.Tag}") .Build(); await container.StartAsync(); diff --git a/tests/Shared/AsyncTestHelpers.cs b/tests/Shared/AsyncTestHelpers.cs index 48bf6c8f5a5..2edff0c209c 100644 --- a/tests/Shared/AsyncTestHelpers.cs +++ b/tests/Shared/AsyncTestHelpers.cs @@ -1,12 +1,168 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics; +using System.Runtime.CompilerServices; using Microsoft.Extensions.Logging; +using System.Threading.Tasks; namespace Microsoft.AspNetCore.InternalTesting; +internal static class TestConstants +{ + // IMPORTANT: If a test fails because these time out, consider adding a new field with a larger value. + // These values are as big as they need to be to test things complete in the expected time. +#if DEBUG + // Shorter duration when running tests with debug. + // Less time waiting for hang unit tests to fail in aspnetcore solution. + public const int DefaultTimeoutDuration = 5 * 1000; + public const int LongTimeoutDuration = 20 * 1000; +#else + public const int DefaultTimeoutDuration = 30 * 1000; + public const int LongTimeoutDuration = 120 * 1000; +#endif + + public static TimeSpan DefaultTimeoutTimeSpan { get; } = TimeSpan.FromMilliseconds(DefaultTimeoutDuration); + public static TimeSpan LongTimeoutTimeSpan { get; } = TimeSpan.FromMilliseconds(LongTimeoutDuration); +} + internal static class AsyncTestHelpers { + private static readonly string s_assemblyName = typeof(TimeoutException).Assembly.GetName().Name!; + + public static CancellationTokenSource CreateDefaultTimeoutTokenSource(int milliseconds = TestConstants.DefaultTimeoutDuration) + { + var cts = new CancellationTokenSource(); + if (!Debugger.IsAttached) + { + cts.CancelAfter(TimeSpan.FromMilliseconds(milliseconds)); + } + return cts; + } + + public static async IAsyncEnumerable DefaultTimeout(this IAsyncEnumerable asyncEnumerable, int milliseconds = TestConstants.DefaultTimeoutDuration, [CallerFilePath] string? filePath = null, [CallerLineNumber] int lineNumber = default) + { + // Wrap the enumerable with an enumerable that times out after exceeding time limit on each iteration. + await using var enumator = asyncEnumerable.GetAsyncEnumerator(); + while (await enumator.MoveNextAsync().DefaultTimeout(milliseconds, filePath, lineNumber)) + { + yield return enumator.Current; + } + } + + public static Task DefaultTimeout(this Task task, int milliseconds = TestConstants.DefaultTimeoutDuration, [CallerFilePath] string? filePath = null, [CallerLineNumber] int lineNumber = default) + { + return task.TimeoutAfter(TimeSpan.FromMilliseconds(milliseconds), filePath, lineNumber); + } + + public static Task DefaultTimeout(this Task task, TimeSpan timeout, [CallerFilePath] string? filePath = null, [CallerLineNumber] int lineNumber = default) + { + return task.TimeoutAfter(timeout, filePath, lineNumber); + } + + public static Task DefaultTimeout(this ValueTask task, int milliseconds = TestConstants.DefaultTimeoutDuration, [CallerFilePath] string? filePath = null, [CallerLineNumber] int lineNumber = default) + { + return task.AsTask().TimeoutAfter(TimeSpan.FromMilliseconds(milliseconds), filePath, lineNumber); + } + + public static Task DefaultTimeout(this ValueTask task, TimeSpan timeout, [CallerFilePath] string? filePath = null, [CallerLineNumber] int lineNumber = default) + { + return task.AsTask().TimeoutAfter(timeout, filePath, lineNumber); + } + + public static Task DefaultTimeout(this Task task, int milliseconds = TestConstants.DefaultTimeoutDuration, [CallerFilePath] string? filePath = null, [CallerLineNumber] int lineNumber = default) + { + return task.TimeoutAfter(TimeSpan.FromMilliseconds(milliseconds), filePath, lineNumber); + } + + public static Task DefaultTimeout(this Task task, TimeSpan timeout, [CallerFilePath] string? filePath = null, [CallerLineNumber] int lineNumber = default) + { + return task.TimeoutAfter(timeout, filePath, lineNumber); + } + + public static Task DefaultTimeout(this ValueTask task, int milliseconds = TestConstants.DefaultTimeoutDuration, [CallerFilePath] string? filePath = null, [CallerLineNumber] int lineNumber = default) + { + return task.AsTask().TimeoutAfter(TimeSpan.FromMilliseconds(milliseconds), filePath, lineNumber); + } + + public static Task DefaultTimeout(this ValueTask task, TimeSpan timeout, [CallerFilePath] string? filePath = null, [CallerLineNumber] int lineNumber = default) + { + return task.AsTask().TimeoutAfter(timeout, filePath, lineNumber); + } + + public static async Task TimeoutAfter(this Task task, TimeSpan timeout, + [CallerFilePath] string? filePath = null, + [CallerLineNumber] int lineNumber = default) + { + // Don't create a timer if the task is already completed + // or the debugger is attached + if (task.IsCompleted || Debugger.IsAttached) + { + return await task.ConfigureAwait(false); + } +#if NET6_0_OR_GREATER + try + { + return await task.WaitAsync(timeout).ConfigureAwait(false); + } + catch (TimeoutException ex) when (ex.Source == s_assemblyName) + { + throw new TimeoutException(CreateMessage(timeout, filePath!, lineNumber)); + } +#else + var cts = new CancellationTokenSource(); + if (task == await Task.WhenAny(task, Task.Delay(timeout, cts.Token)).ConfigureAwait(false)) + { + cts.Cancel(); + return await task.ConfigureAwait(false); + } + else + { + throw new TimeoutException(CreateMessage(timeout, filePath, lineNumber)); + } +#endif + } + + public static async Task TimeoutAfter(this Task task, TimeSpan timeout, + [CallerFilePath] string? filePath = null, + [CallerLineNumber] int lineNumber = default) + { + // Don't create a timer if the task is already completed + // or the debugger is attached + if (task.IsCompleted || Debugger.IsAttached) + { + await task.ConfigureAwait(false); + return; + } +#if NET6_0_OR_GREATER + try + { + await task.WaitAsync(timeout).ConfigureAwait(false); + } + catch (TimeoutException ex) when (ex.Source == s_assemblyName) + { + throw new TimeoutException(CreateMessage(timeout, filePath!, lineNumber)); + } +#else + var cts = new CancellationTokenSource(); + if (task == await Task.WhenAny(task, Task.Delay(timeout, cts.Token)).ConfigureAwait(false)) + { + cts.Cancel(); + await task.ConfigureAwait(false); + } + else + { + throw new TimeoutException(CreateMessage(timeout, filePath, lineNumber)); + } +#endif + } + + private static string CreateMessage(TimeSpan timeout, string filePath, int lineNumber) + => string.IsNullOrEmpty(filePath) + ? $"The operation timed out after reaching the limit of {timeout.TotalMilliseconds}ms." + : $"The operation at {filePath}:{lineNumber} timed out after reaching the limit of {timeout.TotalMilliseconds}ms."; + public static Task AssertIsTrueRetryAsync(Func assert, string message, ILogger? logger = null) { return AssertIsTrueRetryAsync(() => Task.FromResult(assert()), message, logger); diff --git a/tests/Shared/TaskExtensions.cs b/tests/Shared/TaskExtensions.cs deleted file mode 100644 index 53f2ce5cc29..00000000000 --- a/tests/Shared/TaskExtensions.cs +++ /dev/null @@ -1,135 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; - -namespace Microsoft.AspNetCore.InternalTesting; - -internal static class TaskExtensions -{ -#if DEBUG - // Shorter duration when running tests with debug. - // Less time waiting for hang unit tests to fail in aspnetcore solution. - public const int DefaultTimeoutDuration = 5 * 1000; -#else - public const int DefaultTimeoutDuration = 30 * 1000; -#endif - - public static TimeSpan DefaultTimeoutTimeSpan { get; } = TimeSpan.FromMilliseconds(DefaultTimeoutDuration); - - public static Task DefaultTimeout(this Task task, int milliseconds = DefaultTimeoutDuration, [CallerFilePath] string? filePath = null, [CallerLineNumber] int lineNumber = default) - { - return task.TimeoutAfter(TimeSpan.FromMilliseconds(milliseconds), filePath, lineNumber); - } - - public static Task DefaultTimeout(this Task task, TimeSpan timeout, [CallerFilePath] string? filePath = null, [CallerLineNumber] int lineNumber = default) - { - return task.TimeoutAfter(timeout, filePath, lineNumber); - } - - public static Task DefaultTimeout(this ValueTask task, int milliseconds = DefaultTimeoutDuration, [CallerFilePath] string? filePath = null, [CallerLineNumber] int lineNumber = default) - { - return task.AsTask().TimeoutAfter(TimeSpan.FromMilliseconds(milliseconds), filePath, lineNumber); - } - - public static Task DefaultTimeout(this ValueTask task, TimeSpan timeout, [CallerFilePath] string? filePath = null, [CallerLineNumber] int lineNumber = default) - { - return task.AsTask().TimeoutAfter(timeout, filePath, lineNumber); - } - - public static Task DefaultTimeout(this Task task, int milliseconds = DefaultTimeoutDuration, [CallerFilePath] string? filePath = null, [CallerLineNumber] int lineNumber = default) - { - return task.TimeoutAfter(TimeSpan.FromMilliseconds(milliseconds), filePath, lineNumber); - } - - public static Task DefaultTimeout(this Task task, TimeSpan timeout, [CallerFilePath] string? filePath = null, [CallerLineNumber] int lineNumber = default) - { - return task.TimeoutAfter(timeout, filePath, lineNumber); - } - - public static Task DefaultTimeout(this ValueTask task, int milliseconds = DefaultTimeoutDuration, [CallerFilePath] string? filePath = null, [CallerLineNumber] int lineNumber = default) - { - return task.AsTask().TimeoutAfter(TimeSpan.FromMilliseconds(milliseconds), filePath, lineNumber); - } - - public static Task DefaultTimeout(this ValueTask task, TimeSpan timeout, [CallerFilePath] string? filePath = null, [CallerLineNumber] int lineNumber = default) - { - return task.AsTask().TimeoutAfter(timeout, filePath, lineNumber); - } - - [SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Required to maintain compatibility")] - public static async Task TimeoutAfter(this Task task, TimeSpan timeout, - [CallerFilePath] string? filePath = null, - [CallerLineNumber] int lineNumber = default) - { - // Don't create a timer if the task is already completed - // or the debugger is attached - if (task.IsCompleted || Debugger.IsAttached) - { - return await task.ConfigureAwait(false); - } -#if NET6_0_OR_GREATER - try - { - return await task.WaitAsync(timeout).ConfigureAwait(false); - } - catch (TimeoutException ex) when (ex.Source == typeof(TaskExtensions).Namespace) - { - throw new TimeoutException(CreateMessage(timeout, filePath!, lineNumber)); - } -#else - var cts = new CancellationTokenSource(); - if (task == await Task.WhenAny(task, Task.Delay(timeout, cts.Token)).ConfigureAwait(false)) - { - cts.Cancel(); - return await task.ConfigureAwait(false); - } - else - { - throw new TimeoutException(CreateMessage(timeout, filePath, lineNumber)); - } -#endif - } - - [SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Required to maintain compatibility")] - public static async Task TimeoutAfter(this Task task, TimeSpan timeout, - [CallerFilePath] string? filePath = null, - [CallerLineNumber] int lineNumber = default) - { - // Don't create a timer if the task is already completed - // or the debugger is attached - if (task.IsCompleted || Debugger.IsAttached) - { - await task.ConfigureAwait(false); - return; - } -#if NET6_0_OR_GREATER - try - { - await task.WaitAsync(timeout).ConfigureAwait(false); - } - catch (TimeoutException ex) when (ex.Source == typeof(TaskExtensions).Namespace) - { - throw new TimeoutException(CreateMessage(timeout, filePath!, lineNumber)); - } -#else - var cts = new CancellationTokenSource(); - if (task == await Task.WhenAny(task, Task.Delay(timeout, cts.Token)).ConfigureAwait(false)) - { - cts.Cancel(); - await task.ConfigureAwait(false); - } - else - { - throw new TimeoutException(CreateMessage(timeout, filePath, lineNumber)); - } -#endif - } - - private static string CreateMessage(TimeSpan timeout, string filePath, int lineNumber) - => string.IsNullOrEmpty(filePath) - ? $"The operation timed out after reaching the limit of {timeout.TotalMilliseconds}ms." - : $"The operation at {filePath}:{lineNumber} timed out after reaching the limit of {timeout.TotalMilliseconds}ms."; -}