diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 839053f..166cfab 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -96,7 +96,7 @@ jobs: $config = New-PesterConfiguration $config.Run.Path = "tests/PSProxmoxVE.Tests" $config.Run.Exit = $true - $config.Filter.ExcludeTag = @("Integration", "MockIntegration") + $config.Filter.ExcludeTag = @("Integration") $config.Output.Verbosity = "Detailed" $config.TestResult.Enabled = $true $config.TestResult.OutputFormat = "NUnitXml" @@ -111,7 +111,7 @@ jobs: $config = New-PesterConfiguration $config.Run.Path = "tests/PSProxmoxVE.Tests" $config.Run.Exit = $true - $config.Filter.ExcludeTag = @("Integration", "MockIntegration") + $config.Filter.ExcludeTag = @("Integration") $config.Output.Verbosity = "Detailed" $config.TestResult.Enabled = $true $config.TestResult.OutputFormat = "NUnitXml" diff --git a/PSProxmoxVE.sln b/PSProxmoxVE.sln index 2c91f18..2bd52a8 100644 --- a/PSProxmoxVE.sln +++ b/PSProxmoxVE.sln @@ -13,8 +13,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PSProxmoxVE", "src\PSProxmo EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PSProxmoxVE.Core.Tests", "tests\PSProxmoxVE.Core.Tests\PSProxmoxVE.Core.Tests.csproj", "{E5F6A7B8-C9D0-1234-EF12-345678901234}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PSProxmoxVE.MockServer", "tests\PSProxmoxVE.MockServer\PSProxmoxVE.MockServer.csproj", "{B7490D48-1665-41F4-B248-70051EC2F061}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -61,18 +59,6 @@ Global {E5F6A7B8-C9D0-1234-EF12-345678901234}.Release|x64.Build.0 = Release|Any CPU {E5F6A7B8-C9D0-1234-EF12-345678901234}.Release|x86.ActiveCfg = Release|Any CPU {E5F6A7B8-C9D0-1234-EF12-345678901234}.Release|x86.Build.0 = Release|Any CPU - {B7490D48-1665-41F4-B248-70051EC2F061}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B7490D48-1665-41F4-B248-70051EC2F061}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B7490D48-1665-41F4-B248-70051EC2F061}.Debug|x64.ActiveCfg = Debug|Any CPU - {B7490D48-1665-41F4-B248-70051EC2F061}.Debug|x64.Build.0 = Debug|Any CPU - {B7490D48-1665-41F4-B248-70051EC2F061}.Debug|x86.ActiveCfg = Debug|Any CPU - {B7490D48-1665-41F4-B248-70051EC2F061}.Debug|x86.Build.0 = Debug|Any CPU - {B7490D48-1665-41F4-B248-70051EC2F061}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B7490D48-1665-41F4-B248-70051EC2F061}.Release|Any CPU.Build.0 = Release|Any CPU - {B7490D48-1665-41F4-B248-70051EC2F061}.Release|x64.ActiveCfg = Release|Any CPU - {B7490D48-1665-41F4-B248-70051EC2F061}.Release|x64.Build.0 = Release|Any CPU - {B7490D48-1665-41F4-B248-70051EC2F061}.Release|x86.ActiveCfg = Release|Any CPU - {B7490D48-1665-41F4-B248-70051EC2F061}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -81,6 +67,5 @@ Global {C3D4E5F6-A7B8-9012-CDEF-123456789012} = {A1B2C3D4-E5F6-7890-ABCD-EF1234567890} {D4E5F6A7-B8C9-0123-DEF1-234567890123} = {A1B2C3D4-E5F6-7890-ABCD-EF1234567890} {E5F6A7B8-C9D0-1234-EF12-345678901234} = {B2C3D4E5-F6A7-8901-BCDE-F12345678901} - {B7490D48-1665-41F4-B248-70051EC2F061} = {B2C3D4E5-F6A7-8901-BCDE-F12345678901} EndGlobalSection EndGlobal diff --git a/tests/PSProxmoxVE.MockServer/MockPveServer.cs b/tests/PSProxmoxVE.MockServer/MockPveServer.cs deleted file mode 100644 index ff2e461..0000000 --- a/tests/PSProxmoxVE.MockServer/MockPveServer.cs +++ /dev/null @@ -1,209 +0,0 @@ -using System.Security.Cryptography; -using System.Security.Cryptography.X509Certificates; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Hosting.Server; -using Microsoft.AspNetCore.Hosting.Server.Features; -using Microsoft.AspNetCore.Server.Kestrel.Core; -using Microsoft.Extensions.DependencyInjection; -using PSProxmoxVE.MockServer.Routes; - -namespace PSProxmoxVE.MockServer; - -public record RequestRecord(string Method, string Path, string? Body, DateTime Timestamp); - -public class MockPveServer : IDisposable -{ - private readonly WebApplication _app; - private bool _disposed; - - public string BaseUrl { get; } - public int Port { get; } - public List Requests { get; } = new(); - - private static readonly Dictionary _fixtures = new(); - private static readonly object _fixtureLock = new(); - - // Track task status calls per UPID for simulating running -> completed transitions - internal Dictionary TaskStatusCallCounts { get; } = new(); - - private MockPveServer(WebApplication app, int port) - { - _app = app; - Port = port; - BaseUrl = $"https://localhost:{port}"; - } - - public static MockPveServer Start(int port = 0) - { - LoadFixtures(); - - var cert = GenerateSelfSignedCert(); - - var builder = WebApplication.CreateBuilder(); - builder.WebHost.ConfigureKestrel(options => - { - options.ListenLocalhost(port, listenOptions => - { - listenOptions.Protocols = HttpProtocols.Http1AndHttp2; - listenOptions.UseHttps(cert); - }); - }); - - // Suppress default logging noise in tests - builder.Logging.ClearProviders(); - - var app = builder.Build(); - - var server = new MockPveServer(app, port); - - // Request tracking middleware - app.Use(async (context, next) => - { - string? body = null; - if (context.Request.ContentLength > 0 || context.Request.Headers.ContainsKey("Transfer-Encoding")) - { - context.Request.EnableBuffering(); - using var reader = new StreamReader(context.Request.Body, leaveOpen: true); - body = await reader.ReadToEndAsync(); - context.Request.Body.Position = 0; - } - server.Requests.Add(new RequestRecord( - context.Request.Method, - context.Request.Path + context.Request.QueryString, - body, - DateTime.UtcNow)); - await next(); - }); - - // Auth middleware - app.Use(async (context, next) => - { - var path = context.Request.Path.Value ?? ""; - var method = context.Request.Method; - - // Skip auth for ticket creation and version endpoints - bool skipAuth = (path == "/api2/json/access/ticket" && method == "POST") - || (path == "/api2/json/access/ticket" && method == "DELETE") - || (path == "/api2/json/version" && method == "GET"); - - if (!skipAuth) - { - var hasCookie = context.Request.Headers["Cookie"].ToString().Contains("PVEAuthCookie="); - var hasToken = context.Request.Headers["Authorization"].ToString().StartsWith("PVEAPIToken="); - - if (!hasCookie && !hasToken) - { - context.Response.StatusCode = 401; - context.Response.ContentType = "application/json"; - await context.Response.WriteAsync("{\"data\":null,\"errors\":{\"authentication\":\"invalid credentials\"}}"); - return; - } - } - - await next(); - }); - - // Register all routes - app.MapAuthRoutes(); - app.MapVersionRoutes(); - app.MapNodeRoutes(); - app.MapVmRoutes(); - app.MapContainerRoutes(); - app.MapStorageRoutes(); - app.MapNetworkRoutes(); - app.MapUserRoutes(); - app.MapClusterRoutes(); - app.MapTaskRoutes(server); - app.MapSnapshotRoutes(); - - app.StartAsync().GetAwaiter().GetResult(); - - // Resolve the actual port (important when port=0 for random assignment) - var addresses = app.Urls; - var actualPort = port; - var serverInstance = app.Services.GetRequiredService(); - if (serverInstance != null) - { - var addressFeature = serverInstance.Features.Get(); - if (addressFeature != null) - { - var addr = addressFeature.Addresses.FirstOrDefault(); - if (addr != null) - { - var uri = new Uri(addr); - actualPort = uri.Port; - } - } - } - - return new MockPveServer(app, actualPort); - } - - public void Reset() - { - Requests.Clear(); - TaskStatusCallCounts.Clear(); - } - - public void Dispose() - { - if (!_disposed) - { - _disposed = true; - _app.StopAsync().GetAwaiter().GetResult(); - _app.DisposeAsync().AsTask().GetAwaiter().GetResult(); - } - } - - public static string GetFixture(string name) - { - if (_fixtures.TryGetValue(name, out var content)) - return content; - return "{\"data\":null}"; - } - - public static string GenerateUpid(string node, string type, int vmid = 0) - => $"UPID:{node}:{Guid.NewGuid():N}:{DateTimeOffset.UtcNow.ToUnixTimeSeconds():X}:{type}:{vmid}:root@pam:"; - - private static X509Certificate2 GenerateSelfSignedCert() - { - var rsa = RSA.Create(2048); - var req = new CertificateRequest("CN=pve-mock", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); - var cert = req.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(1)); - return cert; - } - - private static void LoadFixtures() - { - lock (_fixtureLock) - { - if (_fixtures.Count > 0) return; - - // Resolve fixtures path relative to the assembly location - var basePath = AppContext.BaseDirectory; - var fixturesPath = Path.GetFullPath(Path.Combine(basePath, "..", "..", "..", "..", "PSProxmoxVE.Core.Tests", "Fixtures")); - - // Fallback: try relative to the project source directory - if (!Directory.Exists(fixturesPath)) - { - fixturesPath = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", "..", "PSProxmoxVE.Core.Tests", "Fixtures")); - } - - if (!Directory.Exists(fixturesPath)) - { - // Last resort: look from the working directory - fixturesPath = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), "..", "PSProxmoxVE.Core.Tests", "Fixtures")); - } - - if (Directory.Exists(fixturesPath)) - { - foreach (var file in Directory.GetFiles(fixturesPath, "*.json")) - { - var name = Path.GetFileNameWithoutExtension(file); - _fixtures[name] = File.ReadAllText(file); - } - } - } - } -} diff --git a/tests/PSProxmoxVE.MockServer/PSProxmoxVE.MockServer.csproj b/tests/PSProxmoxVE.MockServer/PSProxmoxVE.MockServer.csproj deleted file mode 100644 index 6568b3d..0000000 --- a/tests/PSProxmoxVE.MockServer/PSProxmoxVE.MockServer.csproj +++ /dev/null @@ -1,9 +0,0 @@ - - - - net9.0 - enable - enable - - - diff --git a/tests/PSProxmoxVE.MockServer/Program.cs b/tests/PSProxmoxVE.MockServer/Program.cs deleted file mode 100644 index b4fcc6e..0000000 --- a/tests/PSProxmoxVE.MockServer/Program.cs +++ /dev/null @@ -1,22 +0,0 @@ -using PSProxmoxVE.MockServer; - -// When run standalone, start on a fixed port -using var server = MockPveServer.Start(port: 8006); -Console.WriteLine($"Mock Proxmox VE API server running at {server.BaseUrl}"); -Console.WriteLine("Press Ctrl+C to stop."); - -var cts = new CancellationTokenSource(); -Console.CancelKeyPress += (_, e) => -{ - e.Cancel = true; - cts.Cancel(); -}; - -try -{ - await Task.Delay(Timeout.Infinite, cts.Token); -} -catch (OperationCanceledException) -{ - // Graceful shutdown -} diff --git a/tests/PSProxmoxVE.MockServer/Routes/AuthRoutes.cs b/tests/PSProxmoxVE.MockServer/Routes/AuthRoutes.cs deleted file mode 100644 index bf56688..0000000 --- a/tests/PSProxmoxVE.MockServer/Routes/AuthRoutes.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; - -namespace PSProxmoxVE.MockServer.Routes; - -public static class AuthRoutes -{ - public static WebApplication MapAuthRoutes(this WebApplication app) - { - app.MapPost("/api2/json/access/ticket", () => - Results.Content(MockPveServer.GetFixture("pve9_ticket_response"), "application/json")); - - app.MapDelete("/api2/json/access/ticket", () => - Results.Content("{\"data\":null}", "application/json")); - - return app; - } -} diff --git a/tests/PSProxmoxVE.MockServer/Routes/ClusterRoutes.cs b/tests/PSProxmoxVE.MockServer/Routes/ClusterRoutes.cs deleted file mode 100644 index b7a839e..0000000 --- a/tests/PSProxmoxVE.MockServer/Routes/ClusterRoutes.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; - -namespace PSProxmoxVE.MockServer.Routes; - -public static class ClusterRoutes -{ - public static WebApplication MapClusterRoutes(this WebApplication app) - { - app.MapGet("/api2/json/cluster/status", () => - Results.Content(MockPveServer.GetFixture("pve9_cluster_status"), "application/json")); - - return app; - } -} diff --git a/tests/PSProxmoxVE.MockServer/Routes/ContainerRoutes.cs b/tests/PSProxmoxVE.MockServer/Routes/ContainerRoutes.cs deleted file mode 100644 index 513090e..0000000 --- a/tests/PSProxmoxVE.MockServer/Routes/ContainerRoutes.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; - -namespace PSProxmoxVE.MockServer.Routes; - -public static class ContainerRoutes -{ - public static WebApplication MapContainerRoutes(this WebApplication app) - { - app.MapGet("/api2/json/nodes/{node}/lxc", (string node) => - Results.Content(MockPveServer.GetFixture("pve9_containers"), "application/json")); - - app.MapGet("/api2/json/nodes/{node}/lxc/{vmid}/config", (string node, int vmid) => - Results.Content("{\"data\":{\"hostname\":\"test\",\"memory\":512,\"cores\":1}}", "application/json")); - - app.MapPost("/api2/json/nodes/{node}/lxc", (string node) => - Results.Content($"{{\"data\":\"{MockPveServer.GenerateUpid(node, "vzcreate")}\"}}", "application/json")); - - app.MapPost("/api2/json/nodes/{node}/lxc/{vmid}/status/start", (string node, int vmid) => - Results.Content($"{{\"data\":\"{MockPveServer.GenerateUpid(node, "vzstart", vmid)}\"}}", "application/json")); - - app.MapPost("/api2/json/nodes/{node}/lxc/{vmid}/status/stop", (string node, int vmid) => - Results.Content($"{{\"data\":\"{MockPveServer.GenerateUpid(node, "vzstop", vmid)}\"}}", "application/json")); - - app.MapPost("/api2/json/nodes/{node}/lxc/{vmid}/status/shutdown", (string node, int vmid) => - Results.Content($"{{\"data\":\"{MockPveServer.GenerateUpid(node, "vzshutdown", vmid)}\"}}", "application/json")); - - app.MapPut("/api2/json/nodes/{node}/lxc/{vmid}/config", (string node, int vmid) => - Results.Content("{\"data\":null}", "application/json")); - - app.MapDelete("/api2/json/nodes/{node}/lxc/{vmid}", (string node, int vmid) => - Results.Content($"{{\"data\":\"{MockPveServer.GenerateUpid(node, "vzdestroy", vmid)}\"}}", "application/json")); - - return app; - } -} diff --git a/tests/PSProxmoxVE.MockServer/Routes/NetworkRoutes.cs b/tests/PSProxmoxVE.MockServer/Routes/NetworkRoutes.cs deleted file mode 100644 index 58d42a8..0000000 --- a/tests/PSProxmoxVE.MockServer/Routes/NetworkRoutes.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; - -namespace PSProxmoxVE.MockServer.Routes; - -public static class NetworkRoutes -{ - public static WebApplication MapNetworkRoutes(this WebApplication app) - { - app.MapGet("/api2/json/nodes/{node}/network", (string node) => - Results.Content(MockPveServer.GetFixture("pve9_networks"), "application/json")); - - app.MapPost("/api2/json/nodes/{node}/network", (string node) => - Results.Content("{\"data\":null}", "application/json")); - - app.MapPut("/api2/json/nodes/{node}/network/{iface}", (string node, string iface) => - Results.Content("{\"data\":null}", "application/json")); - - app.MapDelete("/api2/json/nodes/{node}/network/{iface}", (string node, string iface) => - Results.Content("{\"data\":null}", "application/json")); - - // Apply network config - app.MapPut("/api2/json/nodes/{node}/network", (string node) => - Results.Content($"{{\"data\":\"{MockPveServer.GenerateUpid(node, "netapply")}\"}}", "application/json")); - - // SDN routes - app.MapGet("/api2/json/cluster/sdn/zones", () => - Results.Content(MockPveServer.GetFixture("pve9_sdn_zones"), "application/json")); - - app.MapGet("/api2/json/cluster/sdn/vnets", () => - Results.Content(MockPveServer.GetFixture("pve9_sdn_vnets"), "application/json")); - - return app; - } -} diff --git a/tests/PSProxmoxVE.MockServer/Routes/NodeRoutes.cs b/tests/PSProxmoxVE.MockServer/Routes/NodeRoutes.cs deleted file mode 100644 index be3bdd2..0000000 --- a/tests/PSProxmoxVE.MockServer/Routes/NodeRoutes.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; - -namespace PSProxmoxVE.MockServer.Routes; - -public static class NodeRoutes -{ - public static WebApplication MapNodeRoutes(this WebApplication app) - { - app.MapGet("/api2/json/nodes", () => - Results.Content(MockPveServer.GetFixture("pve9_nodes"), "application/json")); - - app.MapGet("/api2/json/nodes/{node}/status", (string node) => - Results.Content(MockPveServer.GetFixture("pve9_node_status"), "application/json")); - - return app; - } -} diff --git a/tests/PSProxmoxVE.MockServer/Routes/SnapshotRoutes.cs b/tests/PSProxmoxVE.MockServer/Routes/SnapshotRoutes.cs deleted file mode 100644 index 6fbdb29..0000000 --- a/tests/PSProxmoxVE.MockServer/Routes/SnapshotRoutes.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; - -namespace PSProxmoxVE.MockServer.Routes; - -public static class SnapshotRoutes -{ - public static WebApplication MapSnapshotRoutes(this WebApplication app) - { - app.MapGet("/api2/json/nodes/{node}/qemu/{vmid}/snapshot", (string node, int vmid) => - Results.Content(MockPveServer.GetFixture("pve9_snapshots"), "application/json")); - - app.MapPost("/api2/json/nodes/{node}/qemu/{vmid}/snapshot", (string node, int vmid) => - Results.Content($"{{\"data\":\"{MockPveServer.GenerateUpid(node, "qmsnapshot", vmid)}\"}}", "application/json")); - - app.MapDelete("/api2/json/nodes/{node}/qemu/{vmid}/snapshot/{snapname}", (string node, int vmid, string snapname) => - Results.Content($"{{\"data\":\"{MockPveServer.GenerateUpid(node, "qmdelsnapshot", vmid)}\"}}", "application/json")); - - app.MapPost("/api2/json/nodes/{node}/qemu/{vmid}/snapshot/{snapname}/rollback", (string node, int vmid, string snapname) => - Results.Content($"{{\"data\":\"{MockPveServer.GenerateUpid(node, "qmrollback", vmid)}\"}}", "application/json")); - - return app; - } -} diff --git a/tests/PSProxmoxVE.MockServer/Routes/StorageRoutes.cs b/tests/PSProxmoxVE.MockServer/Routes/StorageRoutes.cs deleted file mode 100644 index 44d075b..0000000 --- a/tests/PSProxmoxVE.MockServer/Routes/StorageRoutes.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; - -namespace PSProxmoxVE.MockServer.Routes; - -public static class StorageRoutes -{ - public static WebApplication MapStorageRoutes(this WebApplication app) - { - app.MapGet("/api2/json/storage", () => - Results.Content(MockPveServer.GetFixture("pve9_storage"), "application/json")); - - app.MapGet("/api2/json/nodes/{node}/storage/{storage}/content", (string node, string storage) => - Results.Content(MockPveServer.GetFixture("pve9_storage_content"), "application/json")); - - app.MapPost("/api2/json/nodes/{node}/storage/{storage}/upload", (string node, string storage) => - Results.Content($"{{\"data\":\"{MockPveServer.GenerateUpid(node, "upload")}\"}}", "application/json")) - .DisableAntiforgery(); - - app.MapPost("/api2/json/storage", () => - Results.Content("{\"data\":null}", "application/json")); - - app.MapDelete("/api2/json/storage/{storage}", (string storage) => - Results.Content("{\"data\":null}", "application/json")); - - return app; - } -} diff --git a/tests/PSProxmoxVE.MockServer/Routes/TaskRoutes.cs b/tests/PSProxmoxVE.MockServer/Routes/TaskRoutes.cs deleted file mode 100644 index 55a64c7..0000000 --- a/tests/PSProxmoxVE.MockServer/Routes/TaskRoutes.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; - -namespace PSProxmoxVE.MockServer.Routes; - -public static class TaskRoutes -{ - public static WebApplication MapTaskRoutes(this WebApplication app, MockPveServer server) - { - app.MapGet("/api2/json/nodes/{node}/tasks/{upid}/status", (string node, string upid) => - { - // Track call count per UPID: first call returns running, subsequent return completed - int count; - lock (server.TaskStatusCallCounts) - { - if (!server.TaskStatusCallCounts.TryGetValue(upid, out count)) - count = 0; - count++; - server.TaskStatusCallCounts[upid] = count; - } - - if (count <= 1) - return Results.Content(MockPveServer.GetFixture("pve9_task_running"), "application/json"); - else - return Results.Content(MockPveServer.GetFixture("pve9_tasks"), "application/json"); - }); - - app.MapGet("/api2/json/nodes/{node}/tasks/{upid}/log", (string node, string upid) => - Results.Content("{\"data\":[{\"n\":1,\"t\":\"starting task\"}]}", "application/json")); - - return app; - } -} diff --git a/tests/PSProxmoxVE.MockServer/Routes/UserRoutes.cs b/tests/PSProxmoxVE.MockServer/Routes/UserRoutes.cs deleted file mode 100644 index 1d74b78..0000000 --- a/tests/PSProxmoxVE.MockServer/Routes/UserRoutes.cs +++ /dev/null @@ -1,58 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; - -namespace PSProxmoxVE.MockServer.Routes; - -public static class UserRoutes -{ - public static WebApplication MapUserRoutes(this WebApplication app) - { - app.MapGet("/api2/json/access/users", () => - Results.Content(MockPveServer.GetFixture("pve9_users"), "application/json")); - - app.MapGet("/api2/json/access/users/{userid}", (string userid) => - { - // Return first user from fixture - var fixture = MockPveServer.GetFixture("pve9_users"); - try - { - var doc = System.Text.Json.JsonDocument.Parse(fixture); - var dataArray = doc.RootElement.GetProperty("data"); - var first = dataArray[0]; - return Results.Content($"{{\"data\":{first.GetRawText()}}}", "application/json"); - } - catch - { - return Results.Content("{\"data\":null}", "application/json"); - } - }); - - app.MapPost("/api2/json/access/users", () => - Results.Content("{\"data\":null}", "application/json")); - - app.MapPut("/api2/json/access/users/{userid}", (string userid) => - Results.Content("{\"data\":null}", "application/json")); - - app.MapDelete("/api2/json/access/users/{userid}", (string userid) => - Results.Content("{\"data\":null}", "application/json")); - - // Roles - app.MapGet("/api2/json/access/roles", () => - Results.Content(MockPveServer.GetFixture("pve9_roles"), "application/json")); - - app.MapPost("/api2/json/access/roles", () => - Results.Content("{\"data\":null}", "application/json")); - - app.MapDelete("/api2/json/access/roles/{roleid}", (string roleid) => - Results.Content("{\"data\":null}", "application/json")); - - // ACL - app.MapGet("/api2/json/access/acl", () => - Results.Content("{\"data\":[]}", "application/json")); - - app.MapPut("/api2/json/access/acl", () => - Results.Content("{\"data\":null}", "application/json")); - - return app; - } -} diff --git a/tests/PSProxmoxVE.MockServer/Routes/VersionRoutes.cs b/tests/PSProxmoxVE.MockServer/Routes/VersionRoutes.cs deleted file mode 100644 index 0b34f5e..0000000 --- a/tests/PSProxmoxVE.MockServer/Routes/VersionRoutes.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; - -namespace PSProxmoxVE.MockServer.Routes; - -public static class VersionRoutes -{ - public static WebApplication MapVersionRoutes(this WebApplication app) - { - app.MapGet("/api2/json/version", () => - Results.Content(MockPveServer.GetFixture("pve9_version"), "application/json")); - - return app; - } -} diff --git a/tests/PSProxmoxVE.MockServer/Routes/VmRoutes.cs b/tests/PSProxmoxVE.MockServer/Routes/VmRoutes.cs deleted file mode 100644 index fd3a08c..0000000 --- a/tests/PSProxmoxVE.MockServer/Routes/VmRoutes.cs +++ /dev/null @@ -1,77 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; - -namespace PSProxmoxVE.MockServer.Routes; - -public static class VmRoutes -{ - public static WebApplication MapVmRoutes(this WebApplication app) - { - app.MapGet("/api2/json/nodes/{node}/qemu", (string node) => - Results.Content(MockPveServer.GetFixture("pve9_vms"), "application/json")); - - app.MapGet("/api2/json/nodes/{node}/qemu/{vmid}/config", (string node, int vmid) => - Results.Content(MockPveServer.GetFixture("pve9_vm_config"), "application/json")); - - app.MapGet("/api2/json/nodes/{node}/qemu/{vmid}/status/current", (string node, int vmid) => - { - // Return first VM from fixture as a single-item response - var fixture = MockPveServer.GetFixture("pve9_vms"); - try - { - var doc = System.Text.Json.JsonDocument.Parse(fixture); - var dataArray = doc.RootElement.GetProperty("data"); - foreach (var item in dataArray.EnumerateArray()) - { - if (item.TryGetProperty("vmid", out var id) && id.GetInt32() == vmid) - return Results.Content($"{{\"data\":{item.GetRawText()}}}", "application/json"); - } - // If no match, return first item - var first = dataArray[0]; - return Results.Content($"{{\"data\":{first.GetRawText()}}}", "application/json"); - } - catch - { - return Results.Content("{\"data\":null}", "application/json"); - } - }); - - app.MapPost("/api2/json/nodes/{node}/qemu", (string node) => - Results.Content($"{{\"data\":\"{MockPveServer.GenerateUpid(node, "qmcreate")}\"}}", "application/json")); - - app.MapPost("/api2/json/nodes/{node}/qemu/{vmid}/status/start", (string node, int vmid) => - Results.Content($"{{\"data\":\"{MockPveServer.GenerateUpid(node, "qmstart", vmid)}\"}}", "application/json")); - - app.MapPost("/api2/json/nodes/{node}/qemu/{vmid}/status/stop", (string node, int vmid) => - Results.Content($"{{\"data\":\"{MockPveServer.GenerateUpid(node, "qmstop", vmid)}\"}}", "application/json")); - - app.MapPost("/api2/json/nodes/{node}/qemu/{vmid}/status/shutdown", (string node, int vmid) => - Results.Content($"{{\"data\":\"{MockPveServer.GenerateUpid(node, "qmshutdown", vmid)}\"}}", "application/json")); - - app.MapPost("/api2/json/nodes/{node}/qemu/{vmid}/status/reset", (string node, int vmid) => - Results.Content($"{{\"data\":\"{MockPveServer.GenerateUpid(node, "qmreset", vmid)}\"}}", "application/json")); - - app.MapPost("/api2/json/nodes/{node}/qemu/{vmid}/status/suspend", (string node, int vmid) => - Results.Content($"{{\"data\":\"{MockPveServer.GenerateUpid(node, "qmsuspend", vmid)}\"}}", "application/json")); - - app.MapPost("/api2/json/nodes/{node}/qemu/{vmid}/status/resume", (string node, int vmid) => - Results.Content($"{{\"data\":\"{MockPveServer.GenerateUpid(node, "qmresume", vmid)}\"}}", "application/json")); - - app.MapPost("/api2/json/nodes/{node}/qemu/{vmid}/clone", (string node, int vmid) => - Results.Content($"{{\"data\":\"{MockPveServer.GenerateUpid(node, "qmclone", vmid)}\"}}", "application/json")); - - app.MapPost("/api2/json/nodes/{node}/qemu/{vmid}/migrate", (string node, int vmid) => - Results.Content($"{{\"data\":\"{MockPveServer.GenerateUpid(node, "qmigrate", vmid)}\"}}", "application/json")); - - app.MapPut("/api2/json/nodes/{node}/qemu/{vmid}/config", (string node, int vmid) => - Results.Content("{\"data\":null}", "application/json")); - - app.MapPut("/api2/json/nodes/{node}/qemu/{vmid}/resize", (string node, int vmid) => - Results.Content("{\"data\":null}", "application/json")); - - app.MapDelete("/api2/json/nodes/{node}/qemu/{vmid}", (string node, int vmid) => - Results.Content($"{{\"data\":\"{MockPveServer.GenerateUpid(node, "qmdestroy", vmid)}\"}}", "application/json")); - - return app; - } -} diff --git a/tests/PSProxmoxVE.Tests/CloudInit/CloudInitCmdlets.Tests.ps1 b/tests/PSProxmoxVE.Tests/CloudInit/CloudInitCmdlets.Tests.ps1 index 2c6c764..4c10544 100644 --- a/tests/PSProxmoxVE.Tests/CloudInit/CloudInitCmdlets.Tests.ps1 +++ b/tests/PSProxmoxVE.Tests/CloudInit/CloudInitCmdlets.Tests.ps1 @@ -14,21 +14,7 @@ #> BeforeAll { - $moduleRoot = Resolve-Path (Join-Path $PSScriptRoot '../../../src/PSProxmoxVE') - $dllCandidates = @( - Join-Path $moduleRoot 'bin/Debug/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Debug/net48/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net48/PSProxmoxVE.dll' - ) - - $script:ModuleDll = $dllCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1 - - if ($null -eq $script:ModuleDll) { - throw "PSProxmoxVE.dll not found. Build the project before running Pester tests." - } - - Import-Module $script:ModuleDll -Force -ErrorAction Stop + . $PSScriptRoot/../_TestHelper.ps1 $script:Availability = @{} foreach ($name in @('Get-PveCloudInitConfig', 'Set-PveCloudInitConfig', @@ -48,7 +34,7 @@ BeforeAll { # --------------------------------------------------------------------------- Describe 'Cloud-Init cmdlets — manifest declarations' { BeforeAll { - $manifestPath = Join-Path $moduleRoot 'PSProxmoxVE.psd1' + $manifestPath = Join-Path (Get-Module PSProxmoxVE).ModuleBase 'PSProxmoxVE.psd1' $script:Manifest = if (Test-Path $manifestPath) { Import-PowerShellDataFile $manifestPath } else { $null } } diff --git a/tests/PSProxmoxVE.Tests/Connection/Connect-PveServer.Tests.ps1 b/tests/PSProxmoxVE.Tests/Connection/Connect-PveServer.Tests.ps1 index bf4805c..06ef5df 100644 --- a/tests/PSProxmoxVE.Tests/Connection/Connect-PveServer.Tests.ps1 +++ b/tests/PSProxmoxVE.Tests/Connection/Connect-PveServer.Tests.ps1 @@ -10,21 +10,7 @@ BeforeAll { # Resolve the built DLL relative to the repository root. # Adjust the path if your build output directory differs. - $moduleRoot = Resolve-Path (Join-Path $PSScriptRoot '../../../src/PSProxmoxVE') - $dllCandidates = @( - Join-Path $moduleRoot 'bin/Debug/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Debug/net48/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net48/PSProxmoxVE.dll' - ) - - $script:ModuleDll = $dllCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1 - - if ($null -eq $script:ModuleDll) { - throw "PSProxmoxVE.dll not found. Build the project before running Pester tests." - } - - Import-Module $script:ModuleDll -Force -ErrorAction Stop + . $PSScriptRoot/../_TestHelper.ps1 } Describe 'Connect-PveServer' { diff --git a/tests/PSProxmoxVE.Tests/Connection/Disconnect-PveServer.Tests.ps1 b/tests/PSProxmoxVE.Tests/Connection/Disconnect-PveServer.Tests.ps1 index baa0aa9..e0626f4 100644 --- a/tests/PSProxmoxVE.Tests/Connection/Disconnect-PveServer.Tests.ps1 +++ b/tests/PSProxmoxVE.Tests/Connection/Disconnect-PveServer.Tests.ps1 @@ -6,21 +6,7 @@ #> BeforeAll { - $moduleRoot = Resolve-Path (Join-Path $PSScriptRoot '../../../src/PSProxmoxVE') - $dllCandidates = @( - Join-Path $moduleRoot 'bin/Debug/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Debug/net48/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net48/PSProxmoxVE.dll' - ) - - $script:ModuleDll = $dllCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1 - - if ($null -eq $script:ModuleDll) { - throw "PSProxmoxVE.dll not found. Build the project before running Pester tests." - } - - Import-Module $script:ModuleDll -Force -ErrorAction Stop + . $PSScriptRoot/../_TestHelper.ps1 } Describe 'Disconnect-PveServer' { diff --git a/tests/PSProxmoxVE.Tests/Connection/Test-PveConnection.Tests.ps1 b/tests/PSProxmoxVE.Tests/Connection/Test-PveConnection.Tests.ps1 index 96de72d..55e0cf3 100644 --- a/tests/PSProxmoxVE.Tests/Connection/Test-PveConnection.Tests.ps1 +++ b/tests/PSProxmoxVE.Tests/Connection/Test-PveConnection.Tests.ps1 @@ -6,21 +6,7 @@ #> BeforeAll { - $moduleRoot = Resolve-Path (Join-Path $PSScriptRoot '../../../src/PSProxmoxVE') - $dllCandidates = @( - Join-Path $moduleRoot 'bin/Debug/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Debug/net48/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net48/PSProxmoxVE.dll' - ) - - $script:ModuleDll = $dllCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1 - - if ($null -eq $script:ModuleDll) { - throw "PSProxmoxVE.dll not found. Build the project before running Pester tests." - } - - Import-Module $script:ModuleDll -Force -ErrorAction Stop + . $PSScriptRoot/../_TestHelper.ps1 } Describe 'Test-PveConnection' { diff --git a/tests/PSProxmoxVE.Tests/Containers/ContainerLifecycle.Tests.ps1 b/tests/PSProxmoxVE.Tests/Containers/ContainerLifecycle.Tests.ps1 index fd54d6e..67399a2 100644 --- a/tests/PSProxmoxVE.Tests/Containers/ContainerLifecycle.Tests.ps1 +++ b/tests/PSProxmoxVE.Tests/Containers/ContainerLifecycle.Tests.ps1 @@ -10,21 +10,7 @@ #> BeforeAll { - $moduleRoot = Resolve-Path (Join-Path $PSScriptRoot '../../../src/PSProxmoxVE') - $dllCandidates = @( - Join-Path $moduleRoot 'bin/Debug/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Debug/net48/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net48/PSProxmoxVE.dll' - ) - - $script:ModuleDll = $dllCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1 - - if ($null -eq $script:ModuleDll) { - throw "PSProxmoxVE.dll not found. Build the project before running Pester tests." - } - - Import-Module $script:ModuleDll -Force -ErrorAction Stop + . $PSScriptRoot/../_TestHelper.ps1 # Pre-calculate availability for each cmdlet. $script:Availability = @{} diff --git a/tests/PSProxmoxVE.Tests/Containers/Get-PveContainer.Tests.ps1 b/tests/PSProxmoxVE.Tests/Containers/Get-PveContainer.Tests.ps1 index 2a13cb2..7a8c1f4 100644 --- a/tests/PSProxmoxVE.Tests/Containers/Get-PveContainer.Tests.ps1 +++ b/tests/PSProxmoxVE.Tests/Containers/Get-PveContainer.Tests.ps1 @@ -10,21 +10,7 @@ #> BeforeAll { - $moduleRoot = Resolve-Path (Join-Path $PSScriptRoot '../../../src/PSProxmoxVE') - $dllCandidates = @( - Join-Path $moduleRoot 'bin/Debug/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Debug/net48/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net48/PSProxmoxVE.dll' - ) - - $script:ModuleDll = $dllCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1 - - if ($null -eq $script:ModuleDll) { - throw "PSProxmoxVE.dll not found. Build the project before running Pester tests." - } - - Import-Module $script:ModuleDll -Force -ErrorAction Stop + . $PSScriptRoot/../_TestHelper.ps1 $script:CmdExists = $null -ne (Get-Command 'Get-PveContainer' -ErrorAction SilentlyContinue) } @@ -34,7 +20,7 @@ Describe 'Get-PveContainer' { Context 'Command existence' { It 'Get-PveContainer should be listed in the module manifest CmdletsToExport' { # The .psd1 declares the cmdlet; implementation may be pending. - $manifestPath = Join-Path $moduleRoot 'PSProxmoxVE.psd1' + $manifestPath = Join-Path (Get-Module PSProxmoxVE).ModuleBase 'PSProxmoxVE.psd1' if (Test-Path $manifestPath) { $manifest = Import-PowerShellDataFile $manifestPath $manifest.CmdletsToExport | Should -Contain 'Get-PveContainer' diff --git a/tests/PSProxmoxVE.Tests/Integration/Integration.Tests.ps1 b/tests/PSProxmoxVE.Tests/Integration/Integration.Tests.ps1 index 4603e48..f3a7796 100644 --- a/tests/PSProxmoxVE.Tests/Integration/Integration.Tests.ps1 +++ b/tests/PSProxmoxVE.Tests/Integration/Integration.Tests.ps1 @@ -27,21 +27,7 @@ BeforeAll { # ----------------------------------------------------------------------- # Resolve and import module # ----------------------------------------------------------------------- - $moduleRoot = Resolve-Path (Join-Path $PSScriptRoot '../../../src/PSProxmoxVE') - $dllCandidates = @( - Join-Path $moduleRoot 'bin/Debug/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Debug/net48/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net48/PSProxmoxVE.dll' - ) - - $moduleDll = $dllCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1 - - if ($null -eq $moduleDll) { - throw "PSProxmoxVE.dll not found. Build the project before running Pester tests." - } - - Import-Module $moduleDll -Force -ErrorAction Stop + . $PSScriptRoot/../_TestHelper.ps1 # ----------------------------------------------------------------------- # Check required environment variables diff --git a/tests/PSProxmoxVE.Tests/MockIntegration/MockServer.Tests.ps1 b/tests/PSProxmoxVE.Tests/MockIntegration/MockServer.Tests.ps1 deleted file mode 100644 index bf95962..0000000 --- a/tests/PSProxmoxVE.Tests/MockIntegration/MockServer.Tests.ps1 +++ /dev/null @@ -1,311 +0,0 @@ -#Requires -Modules Pester - -<# -.SYNOPSIS - Integration tests that run PSProxmoxVE cmdlets against the mock PVE API server. - These validate end-to-end behavior: HTTP requests, auth, deserialization, pipeline. - -.DESCRIPTION - The mock server is started before all tests and stopped after. Each test group - exercises real cmdlet execution against simulated PVE API responses. No real - Proxmox host is needed. -#> - -BeforeAll { - # Find the built mock server - $mockServerProject = Join-Path $PSScriptRoot '../../PSProxmoxVE.MockServer/PSProxmoxVE.MockServer.csproj' - if (-not (Test-Path $mockServerProject)) { - throw "Mock server project not found at $mockServerProject" - } - - # Find the built module DLL - $dllSearchPaths = @( - (Join-Path $PSScriptRoot '../../PSProxmoxVE.MockServer/bin/Release/net9.0/PSProxmoxVE.MockServer.dll'), - (Join-Path $PSScriptRoot '../../PSProxmoxVE.MockServer/bin/Debug/net9.0/PSProxmoxVE.MockServer.dll') - ) - $mockServerDll = $dllSearchPaths | Where-Object { Test-Path $_ } | Select-Object -First 1 - - if (-not $mockServerDll) { - # Build it - $buildOutput = dotnet build $mockServerProject --configuration Release 2>&1 | Out-String - if ($LASTEXITCODE -ne 0) { - throw "Failed to build mock server (exit code $LASTEXITCODE): $buildOutput" - } - $mockServerDll = $dllSearchPaths | Where-Object { Test-Path $_ } | Select-Object -First 1 - if (-not $mockServerDll) { - throw "Mock server build succeeded but DLL not found at expected paths: $($dllSearchPaths -join ', ')" - } - } - - # Start mock server as a background process on a random port - $script:MockPort = Get-Random -Minimum 18000 -Maximum 19000 - $script:MockHost = "localhost" - $script:MockUrl = "https://${script:MockHost}:${script:MockPort}" - - $mockServerDir = Split-Path $mockServerDll -Parent - $script:MockProcess = Start-Process -FilePath 'dotnet' ` - -ArgumentList @($mockServerDll, '--urls', "https://0.0.0.0:$($script:MockPort)") ` - -WorkingDirectory $mockServerDir ` - -PassThru -NoNewWindow -RedirectStandardOutput (Join-Path $TestDrive 'mock-stdout.log') ` - -RedirectStandardError (Join-Path $TestDrive 'mock-stderr.log') - - # Wait for server to become responsive - $maxWait = 30 - $waited = 0 - $ready = $false - while ($waited -lt $maxWait -and -not $ready) { - Start-Sleep -Seconds 1 - $waited++ - try { - # Use .NET directly to skip cert validation - $handler = [System.Net.Http.HttpClientHandler]::new() - $handler.ServerCertificateCustomValidationCallback = { $true } - $client = [System.Net.Http.HttpClient]::new($handler) - $result = $client.GetStringAsync("$($script:MockUrl)/api2/json/version").GetAwaiter().GetResult() - if ($result -match '"version"') { - $ready = $true - } - $client.Dispose() - $handler.Dispose() - } catch { - # Not ready yet - } - } - - if (-not $ready) { - $stderr = if (Test-Path (Join-Path $TestDrive 'mock-stderr.log')) { Get-Content (Join-Path $TestDrive 'mock-stderr.log') -Raw } else { 'N/A' } - throw "Mock server failed to start within ${maxWait}s. Stderr: $stderr" - } - - # Import the module - Import-Module PSProxmoxVE -Force -ErrorAction Stop -} - -AfterAll { - # Stop mock server - if ($script:MockProcess -and -not $script:MockProcess.HasExited) { - $script:MockProcess.Kill() - $script:MockProcess.WaitForExit(5000) - } - - # Disconnect any active session - try { Disconnect-PveServer -ErrorAction SilentlyContinue } catch { } -} - -Describe 'Mock PVE Server - Authentication' -Tag 'MockIntegration' { - - It 'Should connect with API token' { - $session = Connect-PveServer -Server $script:MockHost -Port $script:MockPort ` - -ApiToken 'root@pam!test=00000000-0000-0000-0000-000000000000' ` - -SkipCertificateCheck -PassThru - - $session | Should -Not -BeNullOrEmpty - $session.Hostname | Should -Be $script:MockHost - $session.Port | Should -Be $script:MockPort - $session.AuthMode | Should -Be 'ApiToken' - $session.ServerVersion | Should -Not -BeNullOrEmpty - } - - It 'Should connect with credentials' { - $secPassword = ConvertTo-SecureString 'testpass' -AsPlainText -Force - $cred = [PSCredential]::new('root@pam', $secPassword) - - $session = Connect-PveServer -Server $script:MockHost -Port $script:MockPort ` - -Credential $cred -SkipCertificateCheck -PassThru - - $session | Should -Not -BeNullOrEmpty - $session.AuthMode | Should -Be 'Ticket' - $session.Ticket | Should -Not -BeNullOrEmpty - $session.CsrfToken | Should -Not -BeNullOrEmpty - $session.IsExpired | Should -Be $false - } - - It 'Should report connection status' { - # Connect first - Connect-PveServer -Server $script:MockHost -Port $script:MockPort ` - -ApiToken 'root@pam!test=00000000-0000-0000-0000-000000000000' ` - -SkipCertificateCheck - - $result = Test-PveConnection - $result | Should -Be $true - } - - It 'Should disconnect cleanly' { - Connect-PveServer -Server $script:MockHost -Port $script:MockPort ` - -ApiToken 'root@pam!test=00000000-0000-0000-0000-000000000000' ` - -SkipCertificateCheck - - { Disconnect-PveServer } | Should -Not -Throw - - $result = Test-PveConnection - $result | Should -Be $false - } -} - -Describe 'Mock PVE Server - Node Operations' -Tag 'MockIntegration' { - - BeforeAll { - Connect-PveServer -Server $script:MockHost -Port $script:MockPort ` - -ApiToken 'root@pam!test=00000000-0000-0000-0000-000000000000' ` - -SkipCertificateCheck - } - - AfterAll { - try { Disconnect-PveServer -ErrorAction SilentlyContinue } catch { } - } - - It 'Should list nodes' { - $nodes = Get-PveNode - $nodes | Should -Not -BeNullOrEmpty - $nodes[0].Node | Should -Not -BeNullOrEmpty - $nodes[0].Status | Should -Not -BeNullOrEmpty - } - - It 'Should filter nodes by name' { - $nodes = Get-PveNode -Name 'pve1' - $nodes | Should -Not -BeNullOrEmpty - $nodes | ForEach-Object { $_.Node | Should -Be 'pve1' } - } -} - -Describe 'Mock PVE Server - VM Operations' -Tag 'MockIntegration' { - - BeforeAll { - Connect-PveServer -Server $script:MockHost -Port $script:MockPort ` - -ApiToken 'root@pam!test=00000000-0000-0000-0000-000000000000' ` - -SkipCertificateCheck - } - - AfterAll { - try { Disconnect-PveServer -ErrorAction SilentlyContinue } catch { } - } - - It 'Should list VMs' { - $vms = Get-PveVm -Node 'pve1' - $vms | Should -Not -BeNullOrEmpty - $vms.Count | Should -BeGreaterOrEqual 1 - } - - It 'Should filter VMs by status' { - $running = Get-PveVm -Node 'pve1' -Status 'running' - $running | Should -Not -BeNullOrEmpty - $running | ForEach-Object { $_.Status | Should -Be 'running' } - } - - It 'Should get VM config' { - $config = Get-PveVmConfig -Node 'pve1' -VmId 100 - $config | Should -Not -BeNullOrEmpty - $config.Cores | Should -BeGreaterThan 0 - } - - It 'Should get VM config via pipeline' { - $vms = Get-PveVm -Node 'pve1' -VmId 100 - $config = $vms | Get-PveVmConfig - $config | Should -Not -BeNullOrEmpty - } -} - -Describe 'Mock PVE Server - Storage Operations' -Tag 'MockIntegration' { - - BeforeAll { - Connect-PveServer -Server $script:MockHost -Port $script:MockPort ` - -ApiToken 'root@pam!test=00000000-0000-0000-0000-000000000000' ` - -SkipCertificateCheck - } - - AfterAll { - try { Disconnect-PveServer -ErrorAction SilentlyContinue } catch { } - } - - It 'Should list storage' { - $storage = Get-PveStorage - $storage | Should -Not -BeNullOrEmpty - $storage[0].Storage | Should -Not -BeNullOrEmpty - } - - It 'Should list storage content' { - $content = Get-PveStorageContent -Node 'pve1' -Storage 'local' - $content | Should -Not -BeNullOrEmpty - } -} - -Describe 'Mock PVE Server - Network Operations' -Tag 'MockIntegration' { - - BeforeAll { - Connect-PveServer -Server $script:MockHost -Port $script:MockPort ` - -ApiToken 'root@pam!test=00000000-0000-0000-0000-000000000000' ` - -SkipCertificateCheck - } - - AfterAll { - try { Disconnect-PveServer -ErrorAction SilentlyContinue } catch { } - } - - It 'Should list networks' { - $networks = Get-PveNetwork -Node 'pve1' - $networks | Should -Not -BeNullOrEmpty - $networks[0].Iface | Should -Not -BeNullOrEmpty - } -} - -Describe 'Mock PVE Server - User Operations' -Tag 'MockIntegration' { - - BeforeAll { - Connect-PveServer -Server $script:MockHost -Port $script:MockPort ` - -ApiToken 'root@pam!test=00000000-0000-0000-0000-000000000000' ` - -SkipCertificateCheck - } - - AfterAll { - try { Disconnect-PveServer -ErrorAction SilentlyContinue } catch { } - } - - It 'Should list users' { - $users = Get-PveUser - $users | Should -Not -BeNullOrEmpty - $users[0].UserId | Should -Not -BeNullOrEmpty - } - - It 'Should list roles' { - $roles = Get-PveRole - $roles | Should -Not -BeNullOrEmpty - $roles[0].RoleId | Should -Not -BeNullOrEmpty - } -} - -Describe 'Mock PVE Server - Cluster Operations' -Tag 'MockIntegration' { - - BeforeAll { - Connect-PveServer -Server $script:MockHost -Port $script:MockPort ` - -ApiToken 'root@pam!test=00000000-0000-0000-0000-000000000000' ` - -SkipCertificateCheck - } - - AfterAll { - try { Disconnect-PveServer -ErrorAction SilentlyContinue } catch { } - } - - It 'Should list snapshots' { - $snapshots = Get-PveSnapshot -Node 'pve1' -VmId 100 - $snapshots | Should -Not -BeNullOrEmpty - } -} - -Describe 'Mock PVE Server - Container Operations' -Tag 'MockIntegration' { - - BeforeAll { - Connect-PveServer -Server $script:MockHost -Port $script:MockPort ` - -ApiToken 'root@pam!test=00000000-0000-0000-0000-000000000000' ` - -SkipCertificateCheck - } - - AfterAll { - try { Disconnect-PveServer -ErrorAction SilentlyContinue } catch { } - } - - It 'Should list containers' { - $containers = Get-PveContainer -Node 'pve1' - $containers | Should -Not -BeNullOrEmpty - $containers[0].VmId | Should -BeGreaterThan 0 - } -} diff --git a/tests/PSProxmoxVE.Tests/Network/Get-PveNetwork.Tests.ps1 b/tests/PSProxmoxVE.Tests/Network/Get-PveNetwork.Tests.ps1 index 54edd3e..bac8c21 100644 --- a/tests/PSProxmoxVE.Tests/Network/Get-PveNetwork.Tests.ps1 +++ b/tests/PSProxmoxVE.Tests/Network/Get-PveNetwork.Tests.ps1 @@ -10,21 +10,7 @@ #> BeforeAll { - $moduleRoot = Resolve-Path (Join-Path $PSScriptRoot '../../../src/PSProxmoxVE') - $dllCandidates = @( - Join-Path $moduleRoot 'bin/Debug/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Debug/net48/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net48/PSProxmoxVE.dll' - ) - - $script:ModuleDll = $dllCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1 - - if ($null -eq $script:ModuleDll) { - throw "PSProxmoxVE.dll not found. Build the project before running Pester tests." - } - - Import-Module $script:ModuleDll -Force -ErrorAction Stop + . $PSScriptRoot/../_TestHelper.ps1 $script:Availability = @{} foreach ($name in @('Get-PveNetwork', 'New-PveNetwork', 'Set-PveNetwork', @@ -44,7 +30,7 @@ BeforeAll { # --------------------------------------------------------------------------- Describe 'Network cmdlets — manifest declarations' { BeforeAll { - $manifestPath = Join-Path $moduleRoot 'PSProxmoxVE.psd1' + $manifestPath = Join-Path (Get-Module PSProxmoxVE).ModuleBase 'PSProxmoxVE.psd1' $script:Manifest = if (Test-Path $manifestPath) { Import-PowerShellDataFile $manifestPath } else { $null } } diff --git a/tests/PSProxmoxVE.Tests/Network/SdnCmdlets.Tests.ps1 b/tests/PSProxmoxVE.Tests/Network/SdnCmdlets.Tests.ps1 index aa4111b..1cd7e7f 100644 --- a/tests/PSProxmoxVE.Tests/Network/SdnCmdlets.Tests.ps1 +++ b/tests/PSProxmoxVE.Tests/Network/SdnCmdlets.Tests.ps1 @@ -14,21 +14,7 @@ #> BeforeAll { - $moduleRoot = Resolve-Path (Join-Path $PSScriptRoot '../../../src/PSProxmoxVE') - $dllCandidates = @( - Join-Path $moduleRoot 'bin/Debug/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Debug/net48/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net48/PSProxmoxVE.dll' - ) - - $script:ModuleDll = $dllCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1 - - if ($null -eq $script:ModuleDll) { - throw "PSProxmoxVE.dll not found. Build the project before running Pester tests." - } - - Import-Module $script:ModuleDll -Force -ErrorAction Stop + . $PSScriptRoot/../_TestHelper.ps1 $script:SdnCmdlets = @( 'Get-PveSdnZone', 'New-PveSdnZone', 'Remove-PveSdnZone', @@ -52,7 +38,7 @@ BeforeAll { # --------------------------------------------------------------------------- Describe 'SDN cmdlets — manifest declarations' { BeforeAll { - $manifestPath = Join-Path $moduleRoot 'PSProxmoxVE.psd1' + $manifestPath = Join-Path (Get-Module PSProxmoxVE).ModuleBase 'PSProxmoxVE.psd1' $script:Manifest = if (Test-Path $manifestPath) { Import-PowerShellDataFile $manifestPath } else { $null } } diff --git a/tests/PSProxmoxVE.Tests/Snapshots/SnapshotCmdlets.Tests.ps1 b/tests/PSProxmoxVE.Tests/Snapshots/SnapshotCmdlets.Tests.ps1 index 8456416..2d6c797 100644 --- a/tests/PSProxmoxVE.Tests/Snapshots/SnapshotCmdlets.Tests.ps1 +++ b/tests/PSProxmoxVE.Tests/Snapshots/SnapshotCmdlets.Tests.ps1 @@ -12,21 +12,7 @@ #> BeforeAll { - $moduleRoot = Resolve-Path (Join-Path $PSScriptRoot '../../../src/PSProxmoxVE') - $dllCandidates = @( - Join-Path $moduleRoot 'bin/Debug/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Debug/net48/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net48/PSProxmoxVE.dll' - ) - - $script:ModuleDll = $dllCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1 - - if ($null -eq $script:ModuleDll) { - throw "PSProxmoxVE.dll not found. Build the project before running Pester tests." - } - - Import-Module $script:ModuleDll -Force -ErrorAction Stop + . $PSScriptRoot/../_TestHelper.ps1 $script:Availability = @{} foreach ($name in @('Get-PveSnapshot', 'New-PveSnapshot', @@ -46,7 +32,7 @@ BeforeAll { # --------------------------------------------------------------------------- Describe 'Snapshot cmdlets — manifest declarations' { BeforeAll { - $manifestPath = Join-Path $moduleRoot 'PSProxmoxVE.psd1' + $manifestPath = Join-Path (Get-Module PSProxmoxVE).ModuleBase 'PSProxmoxVE.psd1' $script:Manifest = if (Test-Path $manifestPath) { Import-PowerShellDataFile $manifestPath } else { $null } } diff --git a/tests/PSProxmoxVE.Tests/Storage/Get-PveStorage.Tests.ps1 b/tests/PSProxmoxVE.Tests/Storage/Get-PveStorage.Tests.ps1 index ca68367..8e40591 100644 --- a/tests/PSProxmoxVE.Tests/Storage/Get-PveStorage.Tests.ps1 +++ b/tests/PSProxmoxVE.Tests/Storage/Get-PveStorage.Tests.ps1 @@ -9,21 +9,7 @@ #> BeforeAll { - $moduleRoot = Resolve-Path (Join-Path $PSScriptRoot '../../../src/PSProxmoxVE') - $dllCandidates = @( - Join-Path $moduleRoot 'bin/Debug/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Debug/net48/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net48/PSProxmoxVE.dll' - ) - - $script:ModuleDll = $dllCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1 - - if ($null -eq $script:ModuleDll) { - throw "PSProxmoxVE.dll not found. Build the project before running Pester tests." - } - - Import-Module $script:ModuleDll -Force -ErrorAction Stop + . $PSScriptRoot/../_TestHelper.ps1 $script:Availability = @{} foreach ($name in @('Get-PveStorage', 'Get-PveStorageContent', @@ -43,14 +29,14 @@ BeforeAll { # --------------------------------------------------------------------------- Describe 'Storage cmdlets — manifest declarations' { It 'Get-PveStorage should be declared in CmdletsToExport' { - $manifestPath = Join-Path $moduleRoot 'PSProxmoxVE.psd1' + $manifestPath = Join-Path (Get-Module PSProxmoxVE).ModuleBase 'PSProxmoxVE.psd1' if (-not (Test-Path $manifestPath)) { Set-ItResult -Skipped -Because 'Manifest not found'; return } $manifest = Import-PowerShellDataFile $manifestPath $manifest.CmdletsToExport | Should -Contain 'Get-PveStorage' } It 'Get-PveStorageContent should be declared in CmdletsToExport' { - $manifestPath = Join-Path $moduleRoot 'PSProxmoxVE.psd1' + $manifestPath = Join-Path (Get-Module PSProxmoxVE).ModuleBase 'PSProxmoxVE.psd1' if (-not (Test-Path $manifestPath)) { Set-ItResult -Skipped -Because 'Manifest not found'; return } $manifest = Import-PowerShellDataFile $manifestPath $manifest.CmdletsToExport | Should -Contain 'Get-PveStorageContent' diff --git a/tests/PSProxmoxVE.Tests/Storage/Send-PveIso.Tests.ps1 b/tests/PSProxmoxVE.Tests/Storage/Send-PveIso.Tests.ps1 index f15f483..eb984ab 100644 --- a/tests/PSProxmoxVE.Tests/Storage/Send-PveIso.Tests.ps1 +++ b/tests/PSProxmoxVE.Tests/Storage/Send-PveIso.Tests.ps1 @@ -7,21 +7,7 @@ #> BeforeAll { - $moduleRoot = Resolve-Path (Join-Path $PSScriptRoot '../../../src/PSProxmoxVE') - $dllCandidates = @( - Join-Path $moduleRoot 'bin/Debug/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Debug/net48/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net48/PSProxmoxVE.dll' - ) - - $script:ModuleDll = $dllCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1 - - if ($null -eq $script:ModuleDll) { - throw "PSProxmoxVE.dll not found. Build the project before running Pester tests." - } - - Import-Module $script:ModuleDll -Force -ErrorAction Stop + . $PSScriptRoot/../_TestHelper.ps1 $script:CmdExists = $null -ne (Get-Command 'Send-PveIso' -ErrorAction SilentlyContinue) } @@ -30,7 +16,7 @@ Describe 'Send-PveIso' { Context 'Manifest declaration' { It 'Should be declared in CmdletsToExport' { - $manifestPath = Join-Path $moduleRoot 'PSProxmoxVE.psd1' + $manifestPath = Join-Path (Get-Module PSProxmoxVE).ModuleBase 'PSProxmoxVE.psd1' if (-not (Test-Path $manifestPath)) { Set-ItResult -Skipped -Because 'Manifest not found'; return } $manifest = Import-PowerShellDataFile $manifestPath $manifest.CmdletsToExport | Should -Contain 'Send-PveIso' diff --git a/tests/PSProxmoxVE.Tests/Templates/TemplateCmdlets.Tests.ps1 b/tests/PSProxmoxVE.Tests/Templates/TemplateCmdlets.Tests.ps1 index 301a266..dff1391 100644 --- a/tests/PSProxmoxVE.Tests/Templates/TemplateCmdlets.Tests.ps1 +++ b/tests/PSProxmoxVE.Tests/Templates/TemplateCmdlets.Tests.ps1 @@ -13,21 +13,7 @@ #> BeforeAll { - $moduleRoot = Resolve-Path (Join-Path $PSScriptRoot '../../../src/PSProxmoxVE') - $dllCandidates = @( - Join-Path $moduleRoot 'bin/Debug/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Debug/net48/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net48/PSProxmoxVE.dll' - ) - - $script:ModuleDll = $dllCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1 - - if ($null -eq $script:ModuleDll) { - throw "PSProxmoxVE.dll not found. Build the project before running Pester tests." - } - - Import-Module $script:ModuleDll -Force -ErrorAction Stop + . $PSScriptRoot/../_TestHelper.ps1 $script:Availability = @{} foreach ($name in @('Get-PveTemplate', 'New-PveTemplate', @@ -47,7 +33,7 @@ BeforeAll { # --------------------------------------------------------------------------- Describe 'Template cmdlets — manifest declarations' { BeforeAll { - $manifestPath = Join-Path $moduleRoot 'PSProxmoxVE.psd1' + $manifestPath = Join-Path (Get-Module PSProxmoxVE).ModuleBase 'PSProxmoxVE.psd1' $script:Manifest = if (Test-Path $manifestPath) { Import-PowerShellDataFile $manifestPath } else { $null } } diff --git a/tests/PSProxmoxVE.Tests/Users/ApiTokenCmdlets.Tests.ps1 b/tests/PSProxmoxVE.Tests/Users/ApiTokenCmdlets.Tests.ps1 index f91e80a..80f556c 100644 --- a/tests/PSProxmoxVE.Tests/Users/ApiTokenCmdlets.Tests.ps1 +++ b/tests/PSProxmoxVE.Tests/Users/ApiTokenCmdlets.Tests.ps1 @@ -9,21 +9,7 @@ #> BeforeAll { - $moduleRoot = Resolve-Path (Join-Path $PSScriptRoot '../../../src/PSProxmoxVE') - $dllCandidates = @( - Join-Path $moduleRoot 'bin/Debug/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Debug/net48/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net48/PSProxmoxVE.dll' - ) - - $script:ModuleDll = $dllCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1 - - if ($null -eq $script:ModuleDll) { - throw "PSProxmoxVE.dll not found. Build the project before running Pester tests." - } - - Import-Module $script:ModuleDll -Force -ErrorAction Stop + . $PSScriptRoot/../_TestHelper.ps1 $allNames = @('Get-PveApiToken', 'New-PveApiToken', 'Remove-PveApiToken') @@ -44,7 +30,7 @@ BeforeAll { # --------------------------------------------------------------------------- Describe 'API Token cmdlets — manifest declarations' { BeforeAll { - $manifestPath = Join-Path $moduleRoot 'PSProxmoxVE.psd1' + $manifestPath = Join-Path (Get-Module PSProxmoxVE).ModuleBase 'PSProxmoxVE.psd1' $script:Manifest = if (Test-Path $manifestPath) { Import-PowerShellDataFile $manifestPath } else { $null } } diff --git a/tests/PSProxmoxVE.Tests/Users/UserCmdlets.Tests.ps1 b/tests/PSProxmoxVE.Tests/Users/UserCmdlets.Tests.ps1 index 85c8403..20769b3 100644 --- a/tests/PSProxmoxVE.Tests/Users/UserCmdlets.Tests.ps1 +++ b/tests/PSProxmoxVE.Tests/Users/UserCmdlets.Tests.ps1 @@ -11,21 +11,7 @@ #> BeforeAll { - $moduleRoot = Resolve-Path (Join-Path $PSScriptRoot '../../../src/PSProxmoxVE') - $dllCandidates = @( - Join-Path $moduleRoot 'bin/Debug/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Debug/net48/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net48/PSProxmoxVE.dll' - ) - - $script:ModuleDll = $dllCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1 - - if ($null -eq $script:ModuleDll) { - throw "PSProxmoxVE.dll not found. Build the project before running Pester tests." - } - - Import-Module $script:ModuleDll -Force -ErrorAction Stop + . $PSScriptRoot/../_TestHelper.ps1 $allNames = @( 'Get-PveUser', 'New-PveUser', 'Remove-PveUser', 'Set-PveUser', @@ -50,7 +36,7 @@ BeforeAll { # --------------------------------------------------------------------------- Describe 'User / Role / Permission cmdlets — manifest declarations' { BeforeAll { - $manifestPath = Join-Path $moduleRoot 'PSProxmoxVE.psd1' + $manifestPath = Join-Path (Get-Module PSProxmoxVE).ModuleBase 'PSProxmoxVE.psd1' $script:Manifest = if (Test-Path $manifestPath) { Import-PowerShellDataFile $manifestPath } else { $null } } diff --git a/tests/PSProxmoxVE.Tests/Vms/Get-PveVm.Tests.ps1 b/tests/PSProxmoxVE.Tests/Vms/Get-PveVm.Tests.ps1 index 27eb087..2df2220 100644 --- a/tests/PSProxmoxVE.Tests/Vms/Get-PveVm.Tests.ps1 +++ b/tests/PSProxmoxVE.Tests/Vms/Get-PveVm.Tests.ps1 @@ -6,21 +6,7 @@ #> BeforeAll { - $moduleRoot = Resolve-Path (Join-Path $PSScriptRoot '../../../src/PSProxmoxVE') - $dllCandidates = @( - Join-Path $moduleRoot 'bin/Debug/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Debug/net48/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net48/PSProxmoxVE.dll' - ) - - $script:ModuleDll = $dllCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1 - - if ($null -eq $script:ModuleDll) { - throw "PSProxmoxVE.dll not found. Build the project before running Pester tests." - } - - Import-Module $script:ModuleDll -Force -ErrorAction Stop + . $PSScriptRoot/../_TestHelper.ps1 } Describe 'Get-PveVm' { diff --git a/tests/PSProxmoxVE.Tests/Vms/New-PveVm.Tests.ps1 b/tests/PSProxmoxVE.Tests/Vms/New-PveVm.Tests.ps1 index 4238002..1969f11 100644 --- a/tests/PSProxmoxVE.Tests/Vms/New-PveVm.Tests.ps1 +++ b/tests/PSProxmoxVE.Tests/Vms/New-PveVm.Tests.ps1 @@ -6,21 +6,7 @@ #> BeforeAll { - $moduleRoot = Resolve-Path (Join-Path $PSScriptRoot '../../../src/PSProxmoxVE') - $dllCandidates = @( - Join-Path $moduleRoot 'bin/Debug/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Debug/net48/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net48/PSProxmoxVE.dll' - ) - - $script:ModuleDll = $dllCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1 - - if ($null -eq $script:ModuleDll) { - throw "PSProxmoxVE.dll not found. Build the project before running Pester tests." - } - - Import-Module $script:ModuleDll -Force -ErrorAction Stop + . $PSScriptRoot/../_TestHelper.ps1 } Describe 'New-PveVm' { diff --git a/tests/PSProxmoxVE.Tests/Vms/Remove-PveVm.Tests.ps1 b/tests/PSProxmoxVE.Tests/Vms/Remove-PveVm.Tests.ps1 index f559e5e..570fb1a 100644 --- a/tests/PSProxmoxVE.Tests/Vms/Remove-PveVm.Tests.ps1 +++ b/tests/PSProxmoxVE.Tests/Vms/Remove-PveVm.Tests.ps1 @@ -6,21 +6,7 @@ #> BeforeAll { - $moduleRoot = Resolve-Path (Join-Path $PSScriptRoot '../../../src/PSProxmoxVE') - $dllCandidates = @( - Join-Path $moduleRoot 'bin/Debug/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Debug/net48/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net48/PSProxmoxVE.dll' - ) - - $script:ModuleDll = $dllCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1 - - if ($null -eq $script:ModuleDll) { - throw "PSProxmoxVE.dll not found. Build the project before running Pester tests." - } - - Import-Module $script:ModuleDll -Force -ErrorAction Stop + . $PSScriptRoot/../_TestHelper.ps1 } Describe 'Remove-PveVm' { diff --git a/tests/PSProxmoxVE.Tests/Vms/VmLifecycle.Tests.ps1 b/tests/PSProxmoxVE.Tests/Vms/VmLifecycle.Tests.ps1 index c491d85..007d2da 100644 --- a/tests/PSProxmoxVE.Tests/Vms/VmLifecycle.Tests.ps1 +++ b/tests/PSProxmoxVE.Tests/Vms/VmLifecycle.Tests.ps1 @@ -17,21 +17,7 @@ #> BeforeAll { - $moduleRoot = Resolve-Path (Join-Path $PSScriptRoot '../../../src/PSProxmoxVE') - $dllCandidates = @( - Join-Path $moduleRoot 'bin/Debug/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net9.0/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Debug/net48/PSProxmoxVE.dll' - Join-Path $moduleRoot 'bin/Release/net48/PSProxmoxVE.dll' - ) - - $script:ModuleDll = $dllCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1 - - if ($null -eq $script:ModuleDll) { - throw "PSProxmoxVE.dll not found. Build the project before running Pester tests." - } - - Import-Module $script:ModuleDll -Force -ErrorAction Stop + . $PSScriptRoot/../_TestHelper.ps1 # Helper: assert the standard lifecycle parameter set for Node/VmId/Wait. function Assert-StandardLifecycleParams { diff --git a/tests/PSProxmoxVE.Tests/_TestHelper.ps1 b/tests/PSProxmoxVE.Tests/_TestHelper.ps1 new file mode 100644 index 0000000..57f9722 --- /dev/null +++ b/tests/PSProxmoxVE.Tests/_TestHelper.ps1 @@ -0,0 +1,47 @@ +<# +.SYNOPSIS + Shared module-loading helper for Pester tests. + Dot-source this file inside BeforeAll to import PSProxmoxVE reliably + in both local-dev and CI environments. +#> + +# If the module is already loaded, nothing to do. +if (Get-Module -Name PSProxmoxVE) { return } + +# 1. Try importing by module name (works in CI where the module is +# installed to a PSModulePath location via dotnet publish + copy). +try { + Import-Module PSProxmoxVE -Force -ErrorAction Stop + return +} +catch { + # Module not on PSModulePath — fall through to local-path discovery. +} + +# 2. Discover the built DLL from the local source tree. +# Prefer the framework that matches the running PowerShell edition. +$repoRoot = Resolve-Path (Join-Path $PSScriptRoot '../..') +$moduleRoot = Join-Path $repoRoot 'src/PSProxmoxVE' + +if ($PSVersionTable.PSEdition -eq 'Core') { + $frameworks = @('net9.0', 'net48') +} +else { + $frameworks = @('net48', 'net9.0') +} + +$searchPaths = foreach ($fw in $frameworks) { + # Publish output (has all dependencies co-located) + Join-Path $repoRoot "publish/$fw/PSProxmoxVE.dll" + # Build output + Join-Path $moduleRoot "bin/Debug/$fw/PSProxmoxVE.dll" + Join-Path $moduleRoot "bin/Release/$fw/PSProxmoxVE.dll" +} + +$moduleDll = $searchPaths | Where-Object { Test-Path $_ } | Select-Object -First 1 + +if ($null -eq $moduleDll) { + throw "PSProxmoxVE.dll not found. Build the project before running Pester tests." +} + +Import-Module $moduleDll -Force -ErrorAction Stop diff --git a/tools/Invoke-Tests.ps1 b/tools/Invoke-Tests.ps1 index 748abba..96af64a 100644 --- a/tools/Invoke-Tests.ps1 +++ b/tools/Invoke-Tests.ps1 @@ -270,7 +270,7 @@ function Invoke-PesterUnitTests { $config = New-PesterConfiguration $config.Run.Path = $pesterTestDir - $config.Filter.ExcludeTag = @('Integration', 'MockIntegration') + $config.Filter.ExcludeTag = @('Integration') $config.Output.Verbosity = 'Detailed' $config.Run.PassThru = $true