| File: DotNet\ProcessScopeTests.cs | Web Access |
| Project: src\tests\Aspire.Cli.Tests\Aspire.Cli.Tests.csproj (Aspire.Cli.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.Cli.DotNet; using Aspire.Cli.Tests.TestServices; using Aspire.Shared; using Microsoft.Extensions.Logging.Abstractions; namespace Aspire.Cli.Tests.DotNet; public class ProcessScopeTests { [Fact] public async Task DisposeAsync_PreservesOperationAndCleanupFailures() { var operationFailure = new InvalidOperationException("Original installation failure."); var cleanupFailure = new InvalidOperationException("Could not observe guardian exit."); var execution = new TestProcessExecution( "guardian", [], null, new ProcessInvocationOptions(), (_, _, _) => Task.FromResult((0, (string?)null)), () => 1) { ProcessId = int.MaxValue, DisposeCallback = () => throw cleanupFailure }; await execution.StartAsync(TestContext.Current.CancellationToken); var scope = new ProcessScope(execution, NullLogger.Instance, "test installation"); var exception = await Assert.ThrowsAsync<AggregateException>(() => scope.DisposeAsync(operationFailure).AsTask()); Assert.Collection(exception.InnerExceptions, failure => Assert.Same(operationFailure, failure), failure => Assert.Same(cleanupFailure, failure)); Assert.Equal(1, execution.DisposeCount); Assert.Equal(0, execution.KillCount); } [Fact] public async Task WaitForExitAsync_ForwardsExecutionCancellationAndTerminationFailures() { var terminationFailure = new InvalidOperationException("Could not terminate guardian."); using var cancellation = new CancellationTokenSource(); cancellation.Cancel(); var cancellationFailure = new OperationCanceledException(cancellation.Token); var executionFailure = new AggregateException(cancellationFailure, terminationFailure); var execution = new TestProcessExecution( "guardian", [], null, new ProcessInvocationOptions(), (_, _, _) => Task.FromResult((0, (string?)null)), () => 1) { ProcessId = int.MaxValue, WaitForExitAsyncCallback = (_, token) => token.IsCancellationRequested ? Task.FromException<int>(executionFailure) : Task.FromResult(0) }; await execution.StartAsync(TestContext.Current.CancellationToken); var scope = new ProcessScope(execution, NullLogger.Instance, "cancelled installation"); try { var exception = await Assert.ThrowsAsync<AggregateException>(() => scope.WaitForExitAsync(cancellation.Token)); Assert.Same(executionFailure, exception); Assert.Collection(exception.InnerExceptions, failure => Assert.Same(cancellationFailure, failure), failure => Assert.Same(terminationFailure, failure)); Assert.Equal(0, execution.KillCount); } finally { await scope.DisposeAsync(); } } [Fact] public async Task Constructor_RejectsOwnershipOfTheCaller() { var execution = new TestProcessExecution( "guardian", [], null, new ProcessInvocationOptions(), (_, _, _) => Task.FromResult((0, (string?)null)), () => 1); await using var lifetime = execution; await execution.StartAsync(TestContext.Current.CancellationToken); var exception = Assert.Throws<InvalidOperationException>(() => new ProcessScope(execution, NullLogger.Instance, "invalid scope")); Assert.Equal("A supervised child process scope cannot own its caller.", exception.Message); } }