diff --git a/src/Aspire.Hosting/Publishing/ResourceContainerImageBuilder.cs b/src/Aspire.Hosting/Publishing/ResourceContainerImageBuilder.cs index e846f24bf77..d903ae8dd32 100644 --- a/src/Aspire.Hosting/Publishing/ResourceContainerImageBuilder.cs +++ b/src/Aspire.Hosting/Publishing/ResourceContainerImageBuilder.cs @@ -154,7 +154,7 @@ await task.FailAsync( cancellationToken).ConfigureAwait(false); await step.CompleteAsync("Building container images failed", CompletionState.CompletedWithError, cancellationToken).ConfigureAwait(false); - return; + throw new InvalidOperationException("Container runtime is not running or is unhealthy."); } await task.SucceedAsync( diff --git a/tests/Aspire.Hosting.Tests/Publishing/ResourceContainerImageBuilderTests.cs b/tests/Aspire.Hosting.Tests/Publishing/ResourceContainerImageBuilderTests.cs index 0d3c3423aec..82fdb853d91 100644 --- a/tests/Aspire.Hosting.Tests/Publishing/ResourceContainerImageBuilderTests.cs +++ b/tests/Aspire.Hosting.Tests/Publishing/ResourceContainerImageBuilderTests.cs @@ -381,4 +381,51 @@ public void ContainerBuildOptions_CanSetAllProperties() Assert.Equal("/custom/path", options.OutputPath); Assert.Equal(ContainerTargetPlatform.LinuxArm64, options.TargetPlatform); } + + [Fact] + public async Task BuildImageAsync_ThrowsInvalidOperationException_WhenDockerRuntimeNotAvailable() + { + using var builder = TestDistributedApplicationBuilder.CreateWithTestContainerRegistry(output); + + builder.Services.AddLogging(logging => + { + logging.AddFakeLogging(); + logging.AddXunit(output); + }); + + builder.Services.AddKeyedSingleton("docker", new UnhealthyMockContainerRuntime()); + + var (tempContextPath, tempDockerfilePath) = await DockerfileUtils.CreateTemporaryDockerfileAsync(); + var container = builder.AddDockerfile("container", tempContextPath, tempDockerfilePath); + + using var app = builder.Build(); + + using var cts = new CancellationTokenSource(TestConstants.LongTimeoutTimeSpan); + var imageBuilder = app.Services.GetRequiredService(); + + var exception = await Assert.ThrowsAsync(() => + imageBuilder.BuildImagesAsync([container.Resource], options: null, cts.Token)); + + Assert.Equal("Container runtime is not running or is unhealthy.", exception.Message); + + var collector = app.Services.GetFakeLogCollector(); + var logs = collector.GetSnapshot(); + + Assert.Contains(logs, log => log.Message.Contains("Container runtime is not running or is unhealthy. Cannot build container images.")); + } + + private sealed class UnhealthyMockContainerRuntime : IContainerRuntime + { + public string Name => "MockDocker"; + + public Task CheckIfRunningAsync(CancellationToken cancellationToken) + { + return Task.FromResult(false); + } + + public Task BuildImageAsync(string contextPath, string dockerfilePath, string imageName, ContainerBuildOptions? options, CancellationToken cancellationToken) + { + throw new InvalidOperationException("This mock runtime should not be used for building images."); + } + } }