| File: NativeProviderActivationTests.cs | Web Access |
| Project: src\tests\Aspire.Hosting.Native.Core.Tests\Aspire.Hosting.Native.Core.Tests.csproj (Aspire.Hosting.Native.Core.Tests) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Hosting.Native.Client; using Aspire.Hosting.Native.Core.Tests.TestServices; using Microsoft.Extensions.Logging.Abstractions; namespace Aspire.Hosting.Native.Core.Tests; public class NativeProviderActivationTests { [Fact] public async Task StalledAuthorityAbandonmentUsesAnIndependentConfigurableDeadline() { await using var host = new NativeActivationRpcTestHost(); await using var client = await NativeClient.ConnectAsync(host.Endpoint, "test-token", TimeSpan.FromSeconds(5), TimeProvider.System, TestContext.Current.CancellationToken); var clock = new AdjustableFakeTimeProvider(); var options = new NativeProviderActivationOptions { CleanupTimeout = TimeSpan.FromSeconds(2) }; var directory = Directory.CreateTempSubdirectory("aspire-native-stalled-abandonment-"); try { var activation = NativeProviderActivation.StartAsync(client, "example.failure", Path.Combine(directory.FullName, "missing-provider"), [], options, clock, NullLogger.Instance, TestContext.Current.CancellationToken); await host.AbandonmentStarted.Task.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken); clock.Advance(TimeSpan.FromMilliseconds(1999)); Assert.False(activation.IsCompleted); clock.Advance(TimeSpan.FromMilliseconds(1)); var failure = await Assert.ThrowsAsync<AggregateException>(() => activation.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken)); Assert.Collection(failure.InnerExceptions, error => Assert.IsType<System.ComponentModel.Win32Exception>(error), error => Assert.IsAssignableFrom<OperationCanceledException>(error)); } finally { directory.Delete(recursive: true); } } [Fact] public async Task RepeatedSpawnFailuresDoNotConsumePendingProviderCapacity() { await using var host = await NativeClientTestHost.StartAsync(); await using var client = await NativeClient.ConnectAsync(host.Endpoint, host.Token, TimeSpan.FromSeconds(15), TimeProvider.System, TestContext.Current.CancellationToken); var directory = Directory.CreateTempSubdirectory("aspire-native-provider-failure-"); try { var missing = Path.Combine(directory.FullName, "missing-provider"); for (var index = 0; index < 80; index++) { await Assert.ThrowsAsync<System.ComponentModel.Win32Exception>(() => NativeProviderActivation.StartAsync(client, "example.failure", missing, [], new NativeProviderActivationOptions(), TimeProvider.System, NullLogger.Instance, TestContext.Current.CancellationToken)); } var authority = await client.ExpectIntegrationHostAsync("example.next", TestContext.Current.CancellationToken); Assert.True(await client.AbandonIntegrationHostRegistrationAsync(authority, TestContext.Current.CancellationToken)); } finally { directory.Delete(recursive: true); } } [Fact] public async Task ExitedProviderDisposesProcessAfterDrainingOutput() { if (OperatingSystem.IsWindows()) { Assert.Skip("This process fixture uses a Unix shell."); } await using var host = await NativeProviderProcessTestHost.StartAsync(retainOutput: false); var handle = host.Process.SafeHandle; var activation = new NativeProviderActivation(host.Process, new NativeProviderActivationOptions(), TimeProvider.System); await activation.DisposeAsync().AsTask().WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken); Assert.True(handle.IsClosed); } [Theory] [InlineData(2)] [InlineData(15)] public async Task DescendantHeldOutputCannotOutliveProviderShutdownBudget(int timeoutSeconds) { if (OperatingSystem.IsWindows()) { Assert.Skip("This process fixture uses a Unix shell."); } await using var host = await NativeProviderProcessTestHost.StartAsync(retainOutput: true); var handle = host.Process.SafeHandle; var timerCreated = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var clock = new AdjustableFakeTimeProvider { TimerCreated = dueTime => { if (dueTime == TimeSpan.FromSeconds(timeoutSeconds)) { timerCreated.TrySetResult(); } } }; var activation = new NativeProviderActivation(host.Process, new NativeProviderActivationOptions { ShutdownTimeout = TimeSpan.FromSeconds(timeoutSeconds) }, clock); var disposal = activation.DisposeAsync().AsTask(); await timerCreated.Task.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken); clock.Advance(TimeSpan.FromMilliseconds(timeoutSeconds * 1000 - 1)); Assert.False(disposal.IsCompleted); clock.Advance(TimeSpan.FromMilliseconds(1)); await Assert.ThrowsAsync<TimeoutException>(() => disposal.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken)); Assert.True(handle.IsClosed); Assert.False(host.Descendant!.HasExited); } }