mirror of
https://github.com/GoodOlClint/PSProxmoxVE.git
synced 2026-09-07 20:45:40 +00:00
9a92577794
WaitForStatusTransition and InvokeGuestTask lived on PveCmdletBase with hard-coded qemu/lxc paths, a Thread.Sleep(2000) loop and their own PveHttpClient, so ADR 0015's lock-clear wait and ADR 0020's flock retry could only be exercised through the 45-minute integration lane. Moves both into a new GuestLifecycleService on PveServiceBase, following TaskService's shape: a parameterless ctor, an IPveHttpClient-injecting ctor, and an internal ctor with a Func<TimeSpan, Task> pollDelay seam so a test can drive the poll loop without sleeping. PveCmdletBase keeps the same protected method signatures as thin forwarders wiring WriteVerbose into a single Action<string>? onProgress callback, so none of the 14 cmdlet call sites change. ParseLinks moves to a pure CorosyncLinks.Parse in Core (dictionary plus the malformed entries), with PveCmdletBase.ParseLinks kept as a forwarder that emits the WriteWarning — the same forwarder shape as the lifecycle methods, so the warning stays in one place instead of being copied into the three cluster cmdlets that call it. Behaviour is unchanged: same status/current polling per guest type, same GuestStatusSnapshot.Evaluate lock semantics, same filtered PveApiException catch, same GuestLockRetry wrapping, same PveTaskTimeoutException. Co-authored-by: goodolclint-claude[bot] <323206664+goodolclint-claude[bot]@users.noreply.github.com>
71 lines
2.1 KiB
C#
71 lines
2.1 KiB
C#
using PSProxmoxVE.Core.Utilities;
|
|
using Xunit;
|
|
|
|
namespace PSProxmoxVE.Core.Tests.Utilities
|
|
{
|
|
public class CorosyncLinksTests
|
|
{
|
|
[Fact]
|
|
public void Parse_NullInput_ReturnsNullDictionaryAndNoMalformedEntries()
|
|
{
|
|
var (links, malformed) = CorosyncLinks.Parse(null);
|
|
|
|
Assert.Null(links);
|
|
Assert.Empty(malformed);
|
|
}
|
|
|
|
[Fact]
|
|
public void Parse_WellFormedEntries_ReturnsTrimmedKeysAndValues()
|
|
{
|
|
var (links, malformed) = CorosyncLinks.Parse(new[] { "link0= 10.0.0.1 ", "link1=10.0.0.2" });
|
|
|
|
Assert.NotNull(links);
|
|
Assert.Equal("10.0.0.1", links!["link0"]);
|
|
Assert.Equal("10.0.0.2", links["link1"]);
|
|
Assert.Empty(malformed);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("link0")]
|
|
[InlineData("link0=")]
|
|
[InlineData("=10.0.0.1")]
|
|
[InlineData("")]
|
|
public void Parse_MalformedEntry_IsReportedAndOmitted(string entry)
|
|
{
|
|
var (links, malformed) = CorosyncLinks.Parse(new[] { entry });
|
|
|
|
Assert.Null(links);
|
|
Assert.Equal(new[] { entry }, malformed);
|
|
}
|
|
|
|
[Fact]
|
|
public void Parse_NullEntry_IsReportedAsMalformedRatherThanThrowing()
|
|
{
|
|
var (links, malformed) = CorosyncLinks.Parse(new[] { "link0=10.0.0.1", null! });
|
|
|
|
Assert.NotNull(links);
|
|
Assert.Single(links!);
|
|
Assert.Equal(new[] { "" }, malformed);
|
|
}
|
|
|
|
[Fact]
|
|
public void Parse_ValueContainingEquals_SplitsOnlyOnTheFirstOne()
|
|
{
|
|
var (links, malformed) = CorosyncLinks.Parse(new[] { "link0=10.0.0.1=extra" });
|
|
|
|
Assert.NotNull(links);
|
|
Assert.Equal("10.0.0.1=extra", links!["link0"]);
|
|
Assert.Empty(malformed);
|
|
}
|
|
|
|
[Fact]
|
|
public void Parse_AllEntriesMalformed_ReturnsNullDictionaryWithEveryEntryReported()
|
|
{
|
|
var (links, malformed) = CorosyncLinks.Parse(new[] { "garbage", "link0=" });
|
|
|
|
Assert.Null(links);
|
|
Assert.Equal(new[] { "garbage", "link0=" }, malformed);
|
|
}
|
|
}
|
|
}
|