| File: Publishing\ContainerRuntimeResolverTests.cs | Web Access |
| Project: src\tests\Aspire.Hosting.Tests\Aspire.Hosting.Tests.csproj (Aspire.Hosting.Tests) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #pragma warning disable ASPIRECONTAINERRUNTIME001 using Aspire.Hosting.Dcp; using Aspire.Hosting.Publishing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; namespace Aspire.Hosting.Tests.Publishing; public class ContainerRuntimeResolverTests { private static ContainerRuntimeResolver CreateResolver( string? configuredRuntime = null, IServiceProvider? serviceProvider = null) { var services = new ServiceCollection(); services.AddKeyedSingleton<IContainerRuntime, FakeContainerRuntime>("docker"); services.AddKeyedSingleton<IContainerRuntime, FakeContainerRuntime>("podman"); var sp = serviceProvider ?? services.BuildServiceProvider(); var dcpOptions = Options.Create(new DcpOptions { ContainerRuntime = configuredRuntime }); return new ContainerRuntimeResolver(sp, dcpOptions, NullLoggerFactory.Instance); } [Fact] public async Task ResolveAsync_ReturnsSameInstance_OnSubsequentCalls() { var resolver = CreateResolver(configuredRuntime: "docker"); var first = await resolver.ResolveAsync(); var second = await resolver.ResolveAsync(); Assert.Same(first, second); } [Fact] public async Task ResolveAsync_ReturnsSameTask_WhenCached() { var resolver = CreateResolver(configuredRuntime: "docker"); var task1 = resolver.ResolveAsync(); var task2 = resolver.ResolveAsync(); Assert.Same(task1, task2); await task1; } [Fact] public async Task ResolveAsync_ConfiguredRuntime_ReturnsKeyedService() { var resolver = CreateResolver(configuredRuntime: "podman"); var runtime = await resolver.ResolveAsync(); Assert.NotNull(runtime); } [Fact] public async Task ResolveAsync_AfterCancellation_RetriesWithNewToken() { var resolver = CreateResolver(configuredRuntime: null); // First call with an already-cancelled token using var cts = new CancellationTokenSource(); cts.Cancel(); // The first call may or may not throw depending on timing — // if detection hasn't started yet, the token cancels it immediately. Task<IContainerRuntime>? firstTask = null; try { firstTask = resolver.ResolveAsync(cts.Token); await firstTask; } catch (OperationCanceledException) { // Expected — first attempt was cancelled } // Second call with a valid token should work (not return cached cancellation) if (firstTask is { IsCanceled: true }) { var runtime = await resolver.ResolveAsync(CancellationToken.None); Assert.NotNull(runtime); } } }