diff --git a/src/Aspire.Hosting.Docker/Resources/ServiceNodes/Swarm/UpdateConfig.cs b/src/Aspire.Hosting.Docker/Resources/ServiceNodes/Swarm/UpdateConfig.cs index fac70abfe6c..1701e7776e6 100644 --- a/src/Aspire.Hosting.Docker/Resources/ServiceNodes/Swarm/UpdateConfig.cs +++ b/src/Aspire.Hosting.Docker/Resources/ServiceNodes/Swarm/UpdateConfig.cs @@ -21,7 +21,7 @@ public sealed class UpdateConfig /// be updated simultaneously. /// [YamlMember(Alias = "parallelism")] - public string? Parallelism { get; set; } + public int? Parallelism { get; set; } /// /// Represents the delay between each update operation for a service node in a swarm configuration. @@ -30,10 +30,11 @@ public sealed class UpdateConfig public string? Delay { get; set; } /// - /// Indicates whether the update process should stop and fail upon encountering an error. + /// Gets or sets the action to take when an update fails. + /// Valid values are "continue", "rollback", or "pause" (default). /// [YamlMember(Alias = "failure_action")] - public bool? FailOnError { get; set; } + public string? FailureAction { get; set; } /// /// Gets or sets the duration or interval for monitoring the progress of an update. diff --git a/tests/Aspire.Hosting.Docker.Tests/UpdateConfigTests.cs b/tests/Aspire.Hosting.Docker.Tests/UpdateConfigTests.cs new file mode 100644 index 00000000000..7235ba71628 --- /dev/null +++ b/tests/Aspire.Hosting.Docker.Tests/UpdateConfigTests.cs @@ -0,0 +1,96 @@ +// 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.Docker.Resources; +using Aspire.Hosting.Docker.Resources.ComposeNodes; +using Aspire.Hosting.Docker.Resources.ServiceNodes.Swarm; + +namespace Aspire.Hosting.Docker.Tests; + +public class UpdateConfigTests +{ + [Fact] + public void UpdateConfig_SerializesParallelismAsInteger() + { + // Arrange + var updateConfig = new UpdateConfig + { + Parallelism = 2 + }; + + var composeFile = new ComposeFile + { + Services = new Dictionary + { + ["test-service"] = new Service + { + Name = "test-service", + Image = "nginx", + Deploy = new Deploy + { + UpdateConfig = updateConfig + } + } + } + }; + + // Act + var yaml = composeFile.ToYaml(); + + // Assert - should serialize as integer (correct) + Assert.Contains("parallelism: 2", yaml); + Assert.DoesNotContain("parallelism: \"2\"", yaml); + } + + [Theory] + [InlineData("continue")] + [InlineData("rollback")] + [InlineData("pause")] + public void UpdateConfig_AcceptsValidFailureActionValues(string failureAction) + { + // Arrange & Act + var updateConfig = new UpdateConfig + { + FailureAction = failureAction + }; + + // Assert - no exception should be thrown + Assert.Equal(failureAction, updateConfig.FailureAction); + } + + [Fact] + public void UpdateConfig_NullValuesOmittedFromYaml() + { + // Arrange - Only set some properties + var updateConfig = new UpdateConfig + { + Parallelism = 3, // Set to verify not all are null + FailureAction = null, // Should be omitted + Delay = null // Should be omitted + }; + + var composeFile = new ComposeFile + { + Services = new Dictionary + { + ["test-service"] = new Service + { + Name = "test-service", + Image = "nginx", + Deploy = new Deploy + { + UpdateConfig = updateConfig + } + } + } + }; + + // Act + var yaml = composeFile.ToYaml(); + + // Assert - null values should be omitted + Assert.Contains("parallelism: 3", yaml); + Assert.DoesNotContain("failure_action:", yaml); + Assert.DoesNotContain("delay:", yaml); + } +} \ No newline at end of file