mirror of
https://github.com/GoodOlClint/PSProxmoxVE.git
synced 2026-07-26 16:08:13 +00:00
68dadbfdc0
Phase 1 — Trivial fixes: - F071: Add Uri.EscapeDataString to GetPveTemplateCmdlet node path - F077: Add ValidateRange(100, 999999999) to GetPveTaskListCmdlet.VmId - F076: Create .github/dependabot.yml (nuget + github-actions, weekly) - F079: Fix unit-tests.yml dotnet SDK from 9.0.x to 10.0.x - F048: Mark wont_fix — sync-over-async accepted for PS 5.1 compat Phase 2 — Framework targeting (D009 compliance): - F047: Reduce publishable csproj to netstandard2.0 only, remove all #if NET48/NETSTANDARD2_0 conditionals from PveHttpClient.cs, restructure build.yml for netstandard2.0 publish + net10.0/net48 tests - F064: Resolved by F047 — SMA 7.5.0 ItemGroup removed with net10.0 TFM - F070: Add PS 5.1 smoke-test job to publish.yml (windows-latest) Phase 3 — IPveHttpClient interface extraction (F045): - Extract IPveHttpClient interface from PveHttpClient - Add constructor injection to all 14 service classes - Services use injected client when available, create+dispose when not Phase 4 — Service unit tests (F078): - 196 new xUnit tests across 10 service test files - All services tested via Moq-mocked IPveHttpClient - Total test count: 382 (was 186) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
146 lines
4.6 KiB
C#
146 lines
4.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Threading.Tasks;
|
|
using Moq;
|
|
using Xunit;
|
|
using PSProxmoxVE.Core.Authentication;
|
|
using PSProxmoxVE.Core.Client;
|
|
using PSProxmoxVE.Core.Services;
|
|
|
|
namespace PSProxmoxVE.Core.Tests.Services
|
|
{
|
|
public class PoolServiceTests
|
|
{
|
|
private static PveSession CreateSession()
|
|
{
|
|
return new PveSession("pve1.example.com", 8006, true, "PVE:root@pam:TEST_TOKEN");
|
|
}
|
|
|
|
[Fact]
|
|
public void GetPools_HappyPath_ReturnsArray()
|
|
{
|
|
// Arrange
|
|
var json = @"{
|
|
""data"": [
|
|
{ ""poolid"": ""dev-pool"", ""comment"": ""Development resources"" },
|
|
{ ""poolid"": ""prod-pool"", ""comment"": ""Production resources"" }
|
|
]
|
|
}";
|
|
|
|
var mockClient = new Mock<IPveHttpClient>();
|
|
mockClient.Setup(c => c.GetAsync("pools"))
|
|
.ReturnsAsync(json);
|
|
|
|
var service = new PoolService(mockClient.Object);
|
|
var session = CreateSession();
|
|
|
|
// Act
|
|
var pools = service.GetPools(session);
|
|
|
|
// Assert
|
|
Assert.Equal(2, pools.Length);
|
|
Assert.Equal("dev-pool", pools[0].PoolId);
|
|
Assert.Equal("Development resources", pools[0].Comment);
|
|
Assert.Equal("prod-pool", pools[1].PoolId);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetPool_HappyPath_ReturnsSinglePool()
|
|
{
|
|
// Arrange
|
|
var json = @"{
|
|
""data"": {
|
|
""poolid"": ""dev-pool"",
|
|
""comment"": ""Development resources"",
|
|
""members"": [
|
|
{ ""id"": ""qemu/100"", ""node"": ""pve1"", ""type"": ""qemu"", ""vmid"": 100 }
|
|
]
|
|
}
|
|
}";
|
|
|
|
var mockClient = new Mock<IPveHttpClient>();
|
|
mockClient.Setup(c => c.GetAsync("pools/dev-pool"))
|
|
.ReturnsAsync(json);
|
|
|
|
var service = new PoolService(mockClient.Object);
|
|
var session = CreateSession();
|
|
|
|
// Act
|
|
var pool = service.GetPool(session, "dev-pool");
|
|
|
|
// Assert
|
|
Assert.NotNull(pool);
|
|
Assert.Equal("dev-pool", pool.PoolId);
|
|
Assert.Equal("Development resources", pool.Comment);
|
|
Assert.NotNull(pool.Members);
|
|
Assert.Single(pool.Members);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreatePool_CallsPostAsync()
|
|
{
|
|
// Arrange
|
|
var mockClient = new Mock<IPveHttpClient>();
|
|
mockClient.Setup(c => c.PostAsync("pools", It.IsAny<Dictionary<string, string>>()))
|
|
.ReturnsAsync("{}");
|
|
|
|
var service = new PoolService(mockClient.Object);
|
|
var session = CreateSession();
|
|
|
|
// Act
|
|
service.CreatePool(session, "test-pool", "A test pool");
|
|
|
|
// Assert
|
|
mockClient.Verify(c => c.PostAsync("pools",
|
|
It.Is<Dictionary<string, string>>(d =>
|
|
d["poolid"] == "test-pool" &&
|
|
d["comment"] == "A test pool")),
|
|
Times.Once);
|
|
}
|
|
|
|
[Fact]
|
|
public void UpdatePool_CallsPutAsync()
|
|
{
|
|
// Arrange
|
|
var mockClient = new Mock<IPveHttpClient>();
|
|
mockClient.Setup(c => c.PutAsync(It.IsAny<string>(), It.IsAny<Dictionary<string, string>>()))
|
|
.ReturnsAsync("{}");
|
|
|
|
var service = new PoolService(mockClient.Object);
|
|
var session = CreateSession();
|
|
|
|
var config = new Dictionary<string, string>
|
|
{
|
|
{ "comment", "Updated comment" }
|
|
};
|
|
|
|
// Act
|
|
service.UpdatePool(session, "dev-pool", config);
|
|
|
|
// Assert
|
|
mockClient.Verify(c => c.PutAsync("pools/dev-pool",
|
|
It.Is<Dictionary<string, string>>(d =>
|
|
d["comment"] == "Updated comment")),
|
|
Times.Once);
|
|
}
|
|
|
|
[Fact]
|
|
public void RemovePool_CallsDeleteAsync()
|
|
{
|
|
// Arrange
|
|
var mockClient = new Mock<IPveHttpClient>();
|
|
mockClient.Setup(c => c.DeleteAsync(It.IsAny<string>()))
|
|
.ReturnsAsync("{}");
|
|
|
|
var service = new PoolService(mockClient.Object);
|
|
var session = CreateSession();
|
|
|
|
// Act
|
|
service.RemovePool(session, "dev-pool");
|
|
|
|
// Assert
|
|
mockClient.Verify(c => c.DeleteAsync("pools/dev-pool"), Times.Once);
|
|
}
|
|
}
|
|
}
|