Răsfoiți Sursa

Merge pull request #174 from Timmoth/Testing-Improvements

Testing improvements
Tim Jones 1 lună în urmă
părinte
comite
7759965d19

+ 1 - 0
Shared.Rcl/CliBootstrap.cs

@@ -429,6 +429,7 @@ public static class CliBootstrap
                 laptops.AddCommand<LaptopGetByNameCommand>("get").WithDescription("Retrieve a Laptop by name.");
                 laptops.AddCommand<LaptopDescribeCommand>("describe")
                     .WithDescription("Show detailed information about a Laptop.");
+                laptops.AddCommand<LaptopSetCommand>("set").WithDescription("Update properties of a laptop.");
                 laptops.AddCommand<LaptopDeleteCommand>("del").WithDescription("Delete a Laptop from the inventory.");
                 laptops.AddCommand<LaptopReportCommand>("summary")
                     .WithDescription("Show a summarized hardware report for all Laptops.");

+ 29 - 0
Shared.Rcl/Commands/Laptops/LaptopSetCommand.cs

@@ -0,0 +1,29 @@
+using Microsoft.Extensions.DependencyInjection;
+using RackPeek.Domain.Resources.Laptops;
+using Spectre.Console;
+using Spectre.Console.Cli;
+
+namespace Shared.Rcl.Commands.Laptops;
+
+public class LaptopSetSettings : LaptopNameSettings
+{
+    [CommandOption("--model")] public string? Model { get; set; }
+}
+
+public class LaptopSetCommand(IServiceProvider provider)
+    : AsyncCommand<LaptopSetSettings>
+{
+    public override async Task<int> ExecuteAsync(
+        CommandContext context,
+        LaptopSetSettings settings,
+        CancellationToken cancellationToken)
+    {
+        using var scope = provider.CreateScope();
+        var useCase = scope.ServiceProvider.GetRequiredService<UpdateLaptopUseCase>();
+
+        await useCase.ExecuteAsync(settings.Name, settings.Model);
+
+        AnsiConsole.MarkupLine($"[green]Laptop '{settings.Name}' updated.[/]");
+        return 0;
+    }
+}

+ 1 - 1
Shared.Rcl/Commands/Routers/RouterSetCommand.cs

@@ -33,7 +33,7 @@ public class RouterSetCommand(
             settings.Managed,
             settings.Poe);
 
-        AnsiConsole.MarkupLine($"[green]Server '{settings.Name}' updated.[/]");
+        AnsiConsole.MarkupLine($"[green]Router '{settings.Name}' updated.[/]");
         return 0;
     }
 }

+ 0 - 124
Tests/EndToEnd/AccessPointE2ETests.cs

@@ -1,124 +0,0 @@
-using Tests.EndToEnd.Infra;
-using Xunit.Abstractions;
-
-namespace Tests.EndToEnd;
-
-[Collection("Yaml CLI tests")]
-public class AccessPointYamlE2ETests(TempYamlCliFixture fs, ITestOutputHelper outputHelper)
-    : IClassFixture<TempYamlCliFixture>
-{
-    private async Task<(string, string)> ExecuteAsync(params string[] args)
-    {
-        outputHelper.WriteLine($"rpk {string.Join(" ", args)}");
-
-        var inputArgs = args.ToArray();
-        var output = await YamlCliTestHost.RunAsync(
-            inputArgs,
-            fs.Root,
-            outputHelper,
-            "config.yaml");
-
-        outputHelper.WriteLine(output);
-
-        var yaml = await File.ReadAllTextAsync(Path.Combine(fs.Root, "config.yaml"));
-        return (output, yaml);
-    }
-
-    [Fact]
-    public async Task accesspoints_cli_workflow_test()
-    {
-        // Add AP
-        var (output, yaml) = await ExecuteAsync("accesspoints", "add", "ap01");
-        Assert.Equal("Access Point 'ap01' added.\n", output);
-        Assert.Contains("name: ap01", yaml);
-
-        // Update AP
-        (output, yaml) = await ExecuteAsync(
-            "accesspoints", "set", "ap01",
-            "--model", "Unifi-U6-Lite",
-            "--speed", "1"
-        );
-        Assert.Equal("Access Point 'ap01' updated.\n", output);
-
-        Assert.Equal("""
-                     version: 1
-                     resources:
-                     - kind: AccessPoint
-                       model: Unifi-U6-Lite
-                       speed: 1
-                       name: ap01
-
-                     """, yaml);
-
-        // Add second AP
-        (output, yaml) = await ExecuteAsync("accesspoints", "add", "ap02");
-        Assert.Equal("Access Point 'ap02' added.\n", output);
-
-        (output, yaml) = await ExecuteAsync(
-            "accesspoints", "set", "ap02",
-            "--model", "Aruba-AP-515",
-            "--speed", "2.5"
-        );
-        Assert.Equal("Access Point 'ap02' updated.\n", output);
-
-        Assert.Equal("""
-                     version: 1
-                     resources:
-                     - kind: AccessPoint
-                       model: Unifi-U6-Lite
-                       speed: 1
-                       name: ap01
-                     - kind: AccessPoint
-                       model: Aruba-AP-515
-                       speed: 2.5
-                       name: ap02
-
-                     """, yaml);
-
-        // Get AP
-        (output, yaml) = await ExecuteAsync("accesspoints", "get", "ap01");
-        Assert.Equal("ap01  Model: Unifi-U6-Lite, Speed: 1Gbps\n", output);
-
-        // List APs
-        (output, yaml) = await ExecuteAsync("accesspoints", "list");
-        Assert.Equal("""
-                     ╭──────┬───────────────┬──────────────╮
-                     │ Name │ Model         │ Speed (Gbps) │
-                     ├──────┼───────────────┼──────────────┤
-                     │ ap01 │ Unifi-U6-Lite │ 1            │
-                     │ ap02 │ Aruba-AP-515  │ 2.5          │
-                     ╰──────┴───────────────┴──────────────╯
-
-                     """, output);
-
-        // Summary
-        (output, yaml) = await ExecuteAsync("accesspoints", "summary");
-        Assert.Equal("""
-                     ╭──────┬───────────────┬──────────────╮
-                     │ Name │ Model         │ Speed (Gbps) │
-                     ├──────┼───────────────┼──────────────┤
-                     │ ap01 │ Unifi-U6-Lite │ 1            │
-                     │ ap02 │ Aruba-AP-515  │ 2.5          │
-                     ╰──────┴───────────────┴──────────────╯
-
-                     """, output);
-
-        // Delete AP
-        (output, yaml) = await ExecuteAsync("accesspoints", "del", "ap02");
-        Assert.Equal("""
-                     Access Point 'ap02' deleted.
-
-                     """, output);
-
-        // List again
-        (output, yaml) = await ExecuteAsync("accesspoints", "list");
-        Assert.Equal("""
-                     ╭──────┬───────────────┬──────────────╮
-                     │ Name │ Model         │ Speed (Gbps) │
-                     ├──────┼───────────────┼──────────────┤
-                     │ ap01 │ Unifi-U6-Lite │ 1            │
-                     ╰──────┴───────────────┴──────────────╯
-
-                     """, output);
-    }
-}

+ 0 - 94
Tests/EndToEnd/DesktopYamlE2ETest.cs

@@ -1,94 +0,0 @@
-using Tests.EndToEnd.Infra;
-using Xunit.Abstractions;
-
-namespace Tests.EndToEnd;
-
-[Collection("Yaml CLI tests")]
-public class DesktopYamlE2ETests(TempYamlCliFixture fs, ITestOutputHelper outputHelper)
-    : IClassFixture<TempYamlCliFixture>
-{
-    private async Task<(string, string)> ExecuteAsync(params string[] args)
-    {
-        outputHelper.WriteLine($"rpk {string.Join(" ", args)}");
-
-        var inputArgs = args.ToArray();
-        var output = await YamlCliTestHost.RunAsync(
-            inputArgs,
-            fs.Root,
-            outputHelper,
-            "config.yaml"
-        );
-
-        outputHelper.WriteLine(output);
-
-        var yaml = await File.ReadAllTextAsync(Path.Combine(fs.Root, "config.yaml"));
-        return (output, yaml);
-    }
-
-    [Fact]
-    public async Task desktops_cli_workflow_test()
-    {
-        await File.WriteAllTextAsync(Path.Combine(fs.Root, "config.yaml"), "");
-
-        var (output, yaml) = await ExecuteAsync("desktops", "add", "workstation01");
-        Assert.Equal("Desktop 'workstation01' added.\n", output);
-        Assert.Contains("name: workstation01", yaml);
-    }
-
-    [Fact]
-    public async Task desktops_tree_cli_workflow_test()
-    {
-        await File.WriteAllTextAsync(Path.Combine(fs.Root, "config.yaml"), "");
-
-        // Add desktop
-        var (output, yaml) = await ExecuteAsync("desktops", "add", "workstation01");
-        Assert.Equal("Desktop 'workstation01' added.\n", output);
-        Assert.Contains("name: workstation01", yaml);
-
-        // Add systems
-        (output, yaml) = await ExecuteAsync("systems", "add", "sys01");
-        Assert.Equal("System 'sys01' added.\n", output);
-
-        (output, yaml) = await ExecuteAsync("systems", "add", "sys02");
-        Assert.Equal("System 'sys02' added.\n", output);
-
-        (output, yaml) = await ExecuteAsync("systems", "add", "sys03");
-        Assert.Equal("System 'sys03' added.\n", output);
-
-        // Attach systems to desktop
-        (output, yaml) = await ExecuteAsync("systems", "set", "sys01", "--runs-on", "workstation01");
-        Assert.Equal("System 'sys01' updated.\n", output);
-
-        (output, yaml) = await ExecuteAsync("systems", "set", "sys02", "--runs-on", "workstation01");
-        Assert.Equal("System 'sys02' updated.\n", output);
-
-        (output, yaml) = await ExecuteAsync("systems", "set", "sys03", "--runs-on", "workstation01");
-        Assert.Equal("System 'sys03' updated.\n", output);
-
-        // Add services
-        (output, yaml) = await ExecuteAsync("services", "add", "immich");
-        Assert.Equal("Service 'immich' added.\n", output);
-
-        (output, yaml) = await ExecuteAsync("services", "add", "paperless");
-        Assert.Equal("Service 'paperless' added.\n", output);
-
-        // Attach services to sys01
-        (output, yaml) = await ExecuteAsync("services", "set", "immich", "--runs-on", "sys01");
-        Assert.Equal("Service 'immich' updated.\n", output);
-
-        (output, yaml) = await ExecuteAsync("services", "set", "paperless", "--runs-on", "sys01");
-        Assert.Equal("Service 'paperless' updated.\n", output);
-
-        // Render tree
-        (output, yaml) = await ExecuteAsync("desktops", "tree", "workstation01");
-        Assert.Equal("""
-                     workstation01
-                     ├── System: sys01
-                     │   ├── Service: immich
-                     │   └── Service: paperless
-                     ├── System: sys02
-                     └── System: sys03
-
-                     """, output);
-    }
-}

+ 56 - 0
Tests/EndToEnd/LaptopTests/LaptopCommandTests.cs

@@ -0,0 +1,56 @@
+using Tests.EndToEnd.Infra;
+using Xunit.Abstractions;
+
+namespace Tests.EndToEnd;
+
+[Collection("Yaml CLI tests")]
+public class LaptopCommandTests(TempYamlCliFixture fs, ITestOutputHelper outputHelper)
+    : IClassFixture<TempYamlCliFixture>
+{
+    private async Task<(string, string)> ExecuteAsync(params string[] args)
+    {
+        var output = await YamlCliTestHost.RunAsync(
+            args,
+            fs.Root,
+            outputHelper,
+            "config.yaml"
+        );
+
+        var yaml = await File.ReadAllTextAsync(Path.Combine(fs.Root, "config.yaml"));
+        return (output, yaml);
+    }
+
+    [Fact]
+    public async Task describe_outputs_expected_information()
+    {
+        await ExecuteAsync("laptops", "add", "lap01");
+        await ExecuteAsync("laptops", "set", "lap01", "--model", "ThinkPad X1 Carbon");
+
+        var (output, _) = await ExecuteAsync("laptops", "describe", "lap01");
+
+        Assert.Contains("lap01", output);
+    }
+
+    [Fact]
+    public async Task help_commands_do_not_throw()
+    {
+        Assert.Contains("Manage Laptop computers", (await ExecuteAsync("laptops", "--help")).Item1);
+        Assert.Contains("Add a new Laptop", (await ExecuteAsync("laptops", "add", "--help")).Item1);
+        Assert.Contains("List all Laptops", (await ExecuteAsync("laptops", "list", "--help")).Item1);
+        Assert.Contains("Retrieve a Laptop", (await ExecuteAsync("laptops", "get", "--help")).Item1);
+        Assert.Contains("Show detailed information", (await ExecuteAsync("laptops", "describe", "--help")).Item1);
+        Assert.Contains("Delete a Laptop", (await ExecuteAsync("laptops", "del", "--help")).Item1);
+        Assert.Contains("Show a summarized hardware report", (await ExecuteAsync("laptops", "summary", "--help")).Item1);
+        Assert.Contains("Display the dependency tree", (await ExecuteAsync("laptops", "tree", "--help")).Item1);
+
+        // CPU help
+        Assert.Contains("Manage CPUs", (await ExecuteAsync("laptops", "cpu", "--help")).Item1);
+        Assert.Contains("Add a CPU", (await ExecuteAsync("laptops", "cpu", "add", "--help")).Item1);
+
+        // Drives help
+        Assert.Contains("Manage storage drives", (await ExecuteAsync("laptops", "drives", "--help")).Item1);
+
+        // GPU help
+        Assert.Contains("Manage GPUs", (await ExecuteAsync("laptops", "gpu", "--help")).Item1);
+    }
+}

+ 99 - 0
Tests/EndToEnd/LaptopTests/LaptopErrorTests.cs

@@ -0,0 +1,99 @@
+using Tests.EndToEnd.Infra;
+using Xunit.Abstractions;
+
+namespace Tests.EndToEnd;
+
+[Collection("Yaml CLI tests")]
+public class LaptopErrorTests(TempYamlCliFixture fs, ITestOutputHelper outputHelper)
+    : IClassFixture<TempYamlCliFixture>
+{
+    private async Task<(string, string)> ExecuteAsync(params string[] args)
+    {
+        var output = await YamlCliTestHost.RunAsync(
+            args,
+            fs.Root,
+            outputHelper,
+            "config.yaml"
+        );
+
+        var yaml = await File.ReadAllTextAsync(Path.Combine(fs.Root, "config.yaml"));
+        return (output, yaml);
+    }
+
+    [Fact]
+    public async Task adding_duplicate_laptop_returns_error()
+    {
+        await ExecuteAsync("laptops", "add", "lap01");
+        var (output, _) = await ExecuteAsync("laptops", "add", "lap01");
+        Assert.Contains("already exists", output, StringComparison.OrdinalIgnoreCase);
+    }
+
+    [Fact]
+    public async Task get_missing_laptop_returns_error()
+    {
+        var (output, _) = await ExecuteAsync("laptops", "get", "ghost");
+        Assert.Contains("not found", output, StringComparison.OrdinalIgnoreCase);
+    }
+
+    [Fact]
+    public async Task delete_missing_laptop_returns_error()
+    {
+        var (output, _) = await ExecuteAsync("laptops", "del", "ghost");
+        Assert.Contains("not found", output, StringComparison.OrdinalIgnoreCase);
+    }
+
+    // CPU errors
+    [Fact]
+    public async Task cpu_add_missing_laptop_returns_error()
+    {
+        var (output, _) = await ExecuteAsync(
+            "laptops", "cpu", "add", "ghost",
+            "--model", "Intel i7",
+            "--cores", "8",
+            "--threads", "16"
+        );
+
+        Assert.Contains("not found", output, StringComparison.OrdinalIgnoreCase);
+    }
+
+    [Fact]
+    public async Task cpu_set_invalid_index_returns_error()
+    {
+        await ExecuteAsync("laptops", "add", "lap01");
+
+        var (output, _) = await ExecuteAsync(
+            "laptops", "cpu", "set", "lap01", "5",
+            "--model", "Intel i7"
+        );
+
+        Assert.Contains("not found", output, StringComparison.OrdinalIgnoreCase);
+    }
+
+    // Drive errors
+    [Fact]
+    public async Task drive_set_invalid_index_returns_error()
+    {
+        await ExecuteAsync("laptops", "add", "lap01");
+
+        var (output, _) = await ExecuteAsync(
+            "laptops", "drives", "set", "lap01", "3",
+            "--type", "ssd"
+        );
+
+        Assert.Contains("not found", output, StringComparison.OrdinalIgnoreCase);
+    }
+
+    // GPU errors
+    [Fact]
+    public async Task gpu_set_invalid_index_returns_error()
+    {
+        await ExecuteAsync("laptops", "add", "lap01");
+
+        var (output, _) = await ExecuteAsync(
+            "laptops", "gpu", "set", "lap01", "2",
+            "--model", "Intel Iris Xe"
+        );
+
+        Assert.Contains("not found", output, StringComparison.OrdinalIgnoreCase);
+    }
+}

+ 100 - 0
Tests/EndToEnd/LaptopTests/LaptopWorkflowTests.cs

@@ -0,0 +1,100 @@
+using Tests.EndToEnd.Infra;
+using Xunit.Abstractions;
+
+namespace Tests.EndToEnd;
+
+[Collection("Yaml CLI tests")]
+public class LaptopWorkflowTests(TempYamlCliFixture fs, ITestOutputHelper outputHelper)
+    : IClassFixture<TempYamlCliFixture>
+{
+    private async Task<(string, string)> ExecuteAsync(params string[] args)
+    {
+        outputHelper.WriteLine($"rpk {string.Join(" ", args)}");
+
+        var output = await YamlCliTestHost.RunAsync(
+            args,
+            fs.Root,
+            outputHelper,
+            "config.yaml"
+        );
+
+        outputHelper.WriteLine(output);
+
+        var yaml = await File.ReadAllTextAsync(Path.Combine(fs.Root, "config.yaml"));
+        return (output, yaml);
+    }
+
+    [Fact]
+    public async Task laptops_cli_workflow_test()
+    {
+        await File.WriteAllTextAsync(Path.Combine(fs.Root, "config.yaml"), "");
+
+        // Add laptop
+        var (output, yaml) = await ExecuteAsync("laptops", "add", "lap01");
+        Assert.Equal("Laptop 'lap01' added.\n", output);
+        Assert.Contains("name: lap01", yaml);
+
+        // Set model
+        (output, yaml) = await ExecuteAsync(
+            "laptops", "set", "lap01",
+            "--model", "ThinkPad X1 Carbon"
+        );
+        Assert.Equal("Laptop 'lap01' updated.\n", output);
+        Assert.Contains("model: ThinkPad X1 Carbon", yaml);
+
+        // Add CPU
+        (output, yaml) = await ExecuteAsync(
+            "laptops", "cpu", "add", "lap01",
+            "--model", "Intel i7-1260P",
+            "--cores", "12",
+            "--threads", "16"
+        );
+        Assert.Equal("CPU added to Laptop 'lap01'.\n", output);
+
+        // Add Drive
+        (output, yaml) = await ExecuteAsync(
+            "laptops", "drives", "add", "lap01",
+            "--type", "ssd",
+            "--size", "512"
+        );
+        Assert.Equal("Drive added to Laptop 'lap01'.\n", output);
+
+        // Add GPU
+        (output, yaml) = await ExecuteAsync(
+            "laptops", "gpu", "add", "lap01",
+            "--model", "Intel Iris Xe",
+            "--vram", "1"
+        );
+        Assert.Equal("GPU added to Laptop 'lap01'.\n", output);
+
+        // Get laptop (rich one-line output)
+        (output, yaml) = await ExecuteAsync("laptops", "get", "lap01");
+        Assert.Equal(
+            "lap01\n",
+            output
+        );
+
+        // List laptops 
+        (output, yaml) = await ExecuteAsync("laptops", "list");
+        Assert.Contains("lap01", output);
+
+        // Summary 
+        (output, yaml) = await ExecuteAsync("laptops", "summary");
+        Assert.Contains("lap01", output);
+
+        // Describe 
+        (output, yaml) = await ExecuteAsync("laptops", "describe", "lap01");
+        Assert.Contains("lap01", output);
+
+        // Tree 
+        (output, yaml) = await ExecuteAsync("laptops", "tree", "lap01");
+        Assert.Contains("lap01", output);
+
+        // Delete laptop
+        (output, yaml) = await ExecuteAsync("laptops", "del", "lap01");
+        Assert.Equal("""
+                     Laptop 'lap01' deleted.
+
+                     """, output);
+    }
+}

+ 54 - 0
Tests/EndToEnd/RouterTests/RouterCommandTests.cs

@@ -0,0 +1,54 @@
+using Tests.EndToEnd.Infra;
+using Xunit.Abstractions;
+
+namespace Tests.EndToEnd;
+
+[Collection("Yaml CLI tests")]
+public class RouterCommandTests(TempYamlCliFixture fs, ITestOutputHelper outputHelper)
+    : IClassFixture<TempYamlCliFixture>
+{
+    private async Task<(string, string)> ExecuteAsync(params string[] args)
+    {
+        var output = await YamlCliTestHost.RunAsync(
+            args,
+            fs.Root,
+            outputHelper,
+            "config.yaml"
+        );
+
+        var yaml = await File.ReadAllTextAsync(Path.Combine(fs.Root, "config.yaml"));
+        return (output, yaml);
+    }
+
+    [Fact]
+    public async Task describe_outputs_expected_information()
+    {
+        await ExecuteAsync("routers", "add", "rt01");
+        await ExecuteAsync("routers", "set", "rt01", "--Model", "Ubiquiti EdgeRouter 4");
+
+        var (output, _) = await ExecuteAsync("routers", "describe", "rt01");
+
+        Assert.Contains("rt01", output);
+        Assert.Contains("Ubiquiti EdgeRouter 4", output);
+        Assert.Contains("Managed", output);
+        Assert.Contains("PoE", output);
+    }
+
+    [Fact]
+    public async Task help_commands_do_not_throw()
+    {
+        Assert.Contains("Manage network routers", (await ExecuteAsync("routers", "--help")).Item1);
+        Assert.Contains("Add a new network router", (await ExecuteAsync("routers", "add", "--help")).Item1);
+        Assert.Contains("List all routers", (await ExecuteAsync("routers", "list", "--help")).Item1);
+        Assert.Contains("Retrieve details", (await ExecuteAsync("routers", "get", "--help")).Item1);
+        Assert.Contains("Show detailed information", (await ExecuteAsync("routers", "describe", "--help")).Item1);
+        Assert.Contains("Update properties", (await ExecuteAsync("routers", "set", "--help")).Item1);
+        Assert.Contains("Delete a router", (await ExecuteAsync("routers", "del", "--help")).Item1);
+
+        // Port help
+        Assert.Contains("Manage ports", (await ExecuteAsync("routers", "port", "--help")).Item1);
+        Assert.Contains("Add a port", (await ExecuteAsync("routers", "port", "add", "--help")).Item1);
+        Assert.Contains("Update a router port", (await ExecuteAsync("routers", "port", "set", "--help")).Item1);
+        Assert.Contains("Remove a port", (await ExecuteAsync("routers", "port", "del", "--help")).Item1);
+    }
+}

+ 92 - 0
Tests/EndToEnd/RouterTests/RouterErrorTests.cs

@@ -0,0 +1,92 @@
+using Tests.EndToEnd.Infra;
+using Xunit.Abstractions;
+
+namespace Tests.EndToEnd;
+
+[Collection("Yaml CLI tests")]
+public class RouterErrorTests(TempYamlCliFixture fs, ITestOutputHelper outputHelper)
+    : IClassFixture<TempYamlCliFixture>
+{
+    private async Task<(string, string)> ExecuteAsync(params string[] args)
+    {
+        var output = await YamlCliTestHost.RunAsync(
+            args,
+            fs.Root,
+            outputHelper,
+            "config.yaml"
+        );
+
+        var yaml = await File.ReadAllTextAsync(Path.Combine(fs.Root, "config.yaml"));
+        return (output, yaml);
+    }
+
+    [Fact]
+    public async Task adding_duplicate_router_returns_error()
+    {
+        await ExecuteAsync("routers", "add", "rt01");
+        var (output, _) = await ExecuteAsync("routers", "add", "rt01");
+        Assert.Contains("already exists", output, StringComparison.OrdinalIgnoreCase);
+    }
+
+    [Fact]
+    public async Task get_missing_router_returns_error()
+    {
+        var (output, _) = await ExecuteAsync("routers", "get", "ghost");
+        Assert.Contains("not found", output, StringComparison.OrdinalIgnoreCase);
+    }
+
+    [Fact]
+    public async Task set_missing_router_returns_error()
+    {
+        var (output, _) = await ExecuteAsync("routers", "set", "ghost", "--Model", "X");
+        Assert.Contains("not found", output, StringComparison.OrdinalIgnoreCase);
+    }
+
+    [Fact]
+    public async Task delete_missing_router_returns_error()
+    {
+        var (output, _) = await ExecuteAsync("routers", "del", "ghost");
+        Assert.Contains("not found", output, StringComparison.OrdinalIgnoreCase);
+    }
+
+    // Port errors
+    [Fact]
+    public async Task port_add_missing_router_returns_error()
+    {
+        var (output, _) = await ExecuteAsync(
+            "routers", "port", "add", "ghost",
+            "--type", "rj45",
+            "--speed", "1",
+            "--count", "8"
+        );
+
+        Assert.Contains("not found", output, StringComparison.OrdinalIgnoreCase);
+    }
+
+    [Fact]
+    public async Task port_set_invalid_index_returns_error()
+    {
+        await ExecuteAsync("routers", "add", "rt01");
+
+        var (output, _) = await ExecuteAsync(
+            "routers", "port", "set", "rt01",
+            "--index", "5",
+            "--type", "rj45"
+        );
+
+        Assert.Contains("not found", output, StringComparison.OrdinalIgnoreCase);
+    }
+
+    [Fact]
+    public async Task port_del_invalid_index_returns_error()
+    {
+        await ExecuteAsync("routers", "add", "rt01");
+
+        var (output, _) = await ExecuteAsync(
+            "routers", "port", "del", "rt01",
+            "--index", "3"
+        );
+
+        Assert.Contains("not found", output, StringComparison.OrdinalIgnoreCase);
+    }
+}

+ 124 - 0
Tests/EndToEnd/RouterTests/RouterWorkflowTests.cs

@@ -0,0 +1,124 @@
+using Tests.EndToEnd.Infra;
+using Xunit.Abstractions;
+
+namespace Tests.EndToEnd;
+
+[Collection("Yaml CLI tests")]
+public class RouterWorkflowTests(TempYamlCliFixture fs, ITestOutputHelper outputHelper)
+    : IClassFixture<TempYamlCliFixture>
+{
+    private async Task<(string, string)> ExecuteAsync(params string[] args)
+    {
+        outputHelper.WriteLine($"rpk {string.Join(" ", args)}");
+
+        var output = await YamlCliTestHost.RunAsync(
+            args,
+            fs.Root,
+            outputHelper,
+            "config.yaml"
+        );
+
+        outputHelper.WriteLine(output);
+
+        var yaml = await File.ReadAllTextAsync(Path.Combine(fs.Root, "config.yaml"));
+        return (output, yaml);
+    }
+
+    [Fact]
+    public async Task routers_cli_workflow_test()
+    {
+        await File.WriteAllTextAsync(Path.Combine(fs.Root, "config.yaml"), "");
+
+        // Add router
+        var (output, yaml) = await ExecuteAsync("routers", "add", "rt01");
+        Assert.Equal("Router 'rt01' added.\n", output);
+        Assert.Contains("name: rt01", yaml);
+
+        // Update router
+        (output, yaml) = await ExecuteAsync(
+            "routers", "set", "rt01",
+            "--Model", "Ubiquiti EdgeRouter 4",
+            "--managed", "true",
+            "--poe", "false"
+        );
+        Assert.Equal("Router 'rt01' updated.\n", output);
+
+        Assert.Equal("""
+                     version: 1
+                     resources:
+                     - kind: Router
+                       model: Ubiquiti EdgeRouter 4
+                       managed: true
+                       poe: false
+                       name: rt01
+
+                     """, yaml);
+
+        // Add second router
+        (output, yaml) = await ExecuteAsync("routers", "add", "rt02");
+        Assert.Equal("Router 'rt02' added.\n", output);
+
+        (output, yaml) = await ExecuteAsync(
+            "routers", "set", "rt02",
+            "--Model", "TP-Link ER605",
+            "--managed", "false",
+            "--poe", "false"
+        );
+        Assert.Equal("Router 'rt02' updated.\n", output);
+
+        Assert.Equal("""
+                     version: 1
+                     resources:
+                     - kind: Router
+                       model: Ubiquiti EdgeRouter 4
+                       managed: true
+                       poe: false
+                       name: rt01
+                     - kind: Router
+                       model: TP-Link ER605
+                       managed: false
+                       poe: false
+                       name: rt02
+
+                     """, yaml);
+
+        // Get router
+        (output, yaml) = await ExecuteAsync("routers", "get", "rt01");
+        Assert.Equal("rt01  Model: Ubiquiti EdgeRouter 4, Managed: Yes, PoE: No\n", output);
+
+        // List routers (strict table)
+        (output, yaml) = await ExecuteAsync("routers", "list");
+        Assert.Equal("""
+                     ╭──────┬───────────────────────┬─────────┬─────┬───────┬──────────────╮
+                     │ Name │ Model                 │ Managed │ PoE │ Ports │ Port Summary │
+                     ├──────┼───────────────────────┼─────────┼─────┼───────┼──────────────┤
+                     │ rt01 │ Ubiquiti EdgeRouter 4 │ yes     │ no  │ 0     │ Unknown      │
+                     │ rt02 │ TP-Link ER605         │ no      │ no  │ 0     │ Unknown      │
+                     ╰──────┴───────────────────────┴─────────┴─────┴───────┴──────────────╯
+
+                     """, output);
+
+        // Summary
+        (output, yaml) = await ExecuteAsync("routers", "summary");
+        Assert.Contains("rt01", output);
+        Assert.Contains("rt02", output);
+
+        // Delete router
+        (output, yaml) = await ExecuteAsync("routers", "del", "rt02");
+        Assert.Equal("""
+                     Router 'rt02' deleted.
+
+                     """, output);
+
+        // List again
+        (output, yaml) = await ExecuteAsync("routers", "list");
+        Assert.Equal("""
+                     ╭──────┬───────────────────────┬─────────┬─────┬───────┬──────────────╮
+                     │ Name │ Model                 │ Managed │ PoE │ Ports │ Port Summary │
+                     ├──────┼───────────────────────┼─────────┼─────┼───────┼──────────────┤
+                     │ rt01 │ Ubiquiti EdgeRouter 4 │ yes     │ no  │ 0     │ Unknown      │
+                     ╰──────┴───────────────────────┴─────────┴─────┴───────┴──────────────╯
+
+                     """, output);
+    }
+}

+ 50 - 0
Tests/EndToEnd/ServerTests/ServerCommandTests.cs

@@ -0,0 +1,50 @@
+using Tests.EndToEnd.Infra;
+using Xunit.Abstractions;
+
+namespace Tests.EndToEnd;
+
+[Collection("Yaml CLI tests")]
+public class ServerCommandTests(TempYamlCliFixture fs, ITestOutputHelper outputHelper)
+    : IClassFixture<TempYamlCliFixture>
+{
+    private async Task<(string output, string yaml)> ExecuteAsync(params string[] args)
+    {
+        var output = await YamlCliTestHost.RunAsync(
+            args,
+            fs.Root,
+            outputHelper,
+            "config.yaml");
+
+        var yaml = await File.ReadAllTextAsync(Path.Combine(fs.Root, "config.yaml"));
+        return (output, yaml);
+    }
+
+    [Fact]
+    public async Task describe_outputs_expected_information()
+    {
+        await ExecuteAsync("servers", "add", "srv01");
+        await ExecuteAsync("servers", "set", "srv01", "--ram", "64");
+
+        var (output, _) = await ExecuteAsync("servers", "describe", "srv01");
+
+        Assert.Contains("srv01", output);
+        Assert.Contains("64", output);
+    }
+
+    [Fact]
+    public async Task help_commands_do_not_throw()
+    {
+        Assert.Contains("Manage servers", (await ExecuteAsync("servers", "--help")).output);
+        Assert.Contains("Add a new server", (await ExecuteAsync("servers", "add", "--help")).output);
+        Assert.Contains("List all servers", (await ExecuteAsync("servers", "get", "--help")).output);
+        Assert.Contains("Display detailed information", (await ExecuteAsync("servers", "describe", "--help")).output);
+        Assert.Contains("Update properties", (await ExecuteAsync("servers", "set", "--help")).output);
+        Assert.Contains("Delete a server", (await ExecuteAsync("servers", "del", "--help")).output);
+        Assert.Contains("Display the dependency tree", (await ExecuteAsync("servers", "tree", "--help")).output);
+
+        Assert.Contains("Manage CPUs", (await ExecuteAsync("servers", "cpu", "--help")).output);
+        Assert.Contains("Manage drives", (await ExecuteAsync("servers", "drive", "--help")).output);
+        Assert.Contains("Manage GPUs", (await ExecuteAsync("servers", "gpu", "--help")).output);
+        Assert.Contains("Manage network interface cards", (await ExecuteAsync("servers", "nic", "--help")).output);
+    }
+}

+ 123 - 0
Tests/EndToEnd/ServerTests/ServerErrorTests.cs

@@ -0,0 +1,123 @@
+using Tests.EndToEnd.Infra;
+using Xunit.Abstractions;
+
+namespace Tests.EndToEnd;
+
+[Collection("Yaml CLI tests")]
+public class ServerErrorTests(TempYamlCliFixture fs, ITestOutputHelper outputHelper)
+    : IClassFixture<TempYamlCliFixture>
+{
+    private async Task<(string output, string yaml)> ExecuteAsync(params string[] args)
+    {
+        var output = await YamlCliTestHost.RunAsync(
+            args,
+            fs.Root,
+            outputHelper,
+            "config.yaml");
+
+        var yaml = await File.ReadAllTextAsync(Path.Combine(fs.Root, "config.yaml"));
+        return (output, yaml);
+    }
+
+    [Fact]
+    public async Task adding_duplicate_server_returns_error()
+    {
+        await ExecuteAsync("servers", "add", "srv01");
+        var (output, _) = await ExecuteAsync("servers", "add", "srv01");
+        Assert.Contains("already exists", output, StringComparison.OrdinalIgnoreCase);
+    }
+
+    [Fact]
+    public async Task get_missing_server_returns_error()
+    {
+        var (output, _) = await ExecuteAsync("servers", "get", "ghost");
+        Assert.Contains("not found", output, StringComparison.OrdinalIgnoreCase);
+    }
+
+    [Fact]
+    public async Task set_missing_server_returns_error()
+    {
+        var (output, _) = await ExecuteAsync("servers", "set", "ghost", "--ram", "64");
+        Assert.Contains("not found", output, StringComparison.OrdinalIgnoreCase);
+    }
+
+    [Fact]
+    public async Task delete_missing_server_returns_error()
+    {
+        var (output, _) = await ExecuteAsync("servers", "del", "ghost");
+        Assert.Contains("not found", output, StringComparison.OrdinalIgnoreCase);
+    }
+
+    // CPU errors
+    [Fact]
+    public async Task cpu_add_missing_server_returns_error()
+    {
+        var (output, _) = await ExecuteAsync(
+            "servers", "cpu", "add", "ghost",
+            "--model", "Xeon",
+            "--cores", "8",
+            "--threads", "16"
+        );
+
+        Assert.Contains("not found", output, StringComparison.OrdinalIgnoreCase);
+    }
+
+    [Fact]
+    public async Task cpu_set_invalid_index_returns_error()
+    {
+        await ExecuteAsync("servers", "add", "srv01");
+
+        var (output, _) = await ExecuteAsync(
+            "servers", "cpu", "set", "srv01",
+            "--index", "5",
+            "--model", "Xeon"
+        );
+
+        Assert.Contains("Not found", output, StringComparison.OrdinalIgnoreCase);
+    }
+
+    // Drive errors
+    [Fact]
+    public async Task drive_set_invalid_index_returns_error()
+    {
+        await ExecuteAsync("servers", "add", "srv01");
+
+        var (output, _) = await ExecuteAsync(
+            "servers", "drive", "set", "srv01",
+            "--index", "3",
+            "--type", "ssd"
+        );
+
+        Assert.Contains("Not found", output, StringComparison.OrdinalIgnoreCase);
+    }
+
+    // GPU errors
+    [Fact]
+    public async Task gpu_set_invalid_index_returns_error()
+    {
+        await ExecuteAsync("servers", "add", "srv01");
+
+        var (output, _) = await ExecuteAsync(
+            "servers", "gpu", "set", "srv01",
+            "--index", "2",
+            "--model", "A2000"
+        );
+
+        Assert.Contains("Not found", output, StringComparison.OrdinalIgnoreCase);
+    }
+
+    // NIC errors
+    [Fact]
+    public async Task nic_set_invalid_index_returns_error()
+    {
+        await ExecuteAsync("servers", "add", "srv01");
+
+        var (output, _) = await ExecuteAsync(
+            "servers", "nic", "set", "srv01",
+            "--index", "4",
+            "--type", "ethernet"
+        );
+
+        Assert.Contains("Validation error", output, StringComparison.OrdinalIgnoreCase);
+    }
+}

+ 141 - 0
Tests/EndToEnd/ServerTests/ServerWorkflowTests.cs

@@ -0,0 +1,141 @@
+using Tests.EndToEnd.Infra;
+using Xunit.Abstractions;
+
+namespace Tests.EndToEnd;
+
+[Collection("Yaml CLI tests")]
+public class ServerWorkflowTests(TempYamlCliFixture fs, ITestOutputHelper outputHelper)
+    : IClassFixture<TempYamlCliFixture>
+{
+    private async Task<(string output, string yaml)> ExecuteAsync(params string[] args)
+    {
+        outputHelper.WriteLine($"rpk {string.Join(" ", args)}");
+
+        var output = await YamlCliTestHost.RunAsync(
+            args,
+            fs.Root,
+            outputHelper,
+            "config.yaml");
+
+        outputHelper.WriteLine(output);
+
+        var yaml = await File.ReadAllTextAsync(Path.Combine(fs.Root, "config.yaml"));
+        return (output, yaml);
+    }
+
+    [Fact]
+    public async Task servers_cli_workflow_test()
+    {
+        await File.WriteAllTextAsync(Path.Combine(fs.Root, "config.yaml"), "");
+
+        // Add server
+        var (output, yaml) = await ExecuteAsync("servers", "add", "srv01");
+        Assert.Equal("Server 'srv01' added.\n", output);
+        Assert.Contains("name: srv01", yaml);
+
+        // Update server
+        (output, yaml) = await ExecuteAsync(
+            "servers", "set", "srv01",
+            "--ram", "128",
+            "--ram_mts", "3200",
+            "--ipmi", "True"
+        );
+        Assert.Equal("Server 'srv01' updated.\n", output);
+
+        Assert.Equal("""
+                     version: 1
+                     resources:
+                     - kind: Server
+                       ram:
+                         size: 128
+                         mts: 3200
+                       ipmi: true
+                       name: srv01
+
+                     """, yaml);
+
+        // Add CPU
+        (output, yaml) = await ExecuteAsync(
+            "servers", "cpu", "add", "srv01",
+            "--model", "Intel Xeon Silver 4310",
+            "--cores", "12",
+            "--threads", "24"
+        );
+        Assert.Equal("CPU added to 'srv01'.\n", output);
+
+        // Add Drive
+        (output, yaml) = await ExecuteAsync(
+            "servers", "drive", "add", "srv01",
+            "--type", "ssd",
+            "--size", "1024"
+        );
+        Assert.Equal("Drive added to 'srv01'.\n", output);
+
+        // Add GPU
+        (output, yaml) = await ExecuteAsync(
+            "servers", "gpu", "add", "srv01",
+            "--model", "NVIDIA A2000",
+            "--vram", "6"
+        );
+        Assert.Equal("GPU added to 'srv01'.\n", output);
+
+        // Add NIC
+        (output, yaml) = await ExecuteAsync(
+            "servers", "nic", "add", "srv01",
+            "--type", "RJ45",
+            "--speed", "10",
+            "--ports", "2"
+        );
+        Assert.Equal("NIC added to 'srv01'.\n", output);
+
+        // Get server
+        (output, yaml) = await ExecuteAsync("servers", "get", "srv01");
+        Assert.Equal(
+            "srv01  RAM: 128 GB, IPMI: yes\n",
+            output
+        );
+        
+
+        
+    // Summary (strict table)
+        (output, yaml) = await ExecuteAsync("servers", "summary");
+        
+        Assert.Equal("""
+                     ╭───────┬────────────┬───────┬────────┬────────────┬───────┬────────────┬──────╮
+                     │ Name  │ CPU        │ C/T   │ RAM    │ Storage    │ NICs  │ GPUs       │ IPMI │
+                     ├───────┼────────────┼───────┼────────┼────────────┼───────┼────────────┼──────┤
+                     │ srv01 │ 1× Intel   │ 12/24 │ 128 GB │ 1024 GB    │ 2×10G │ 1× NVIDIA  │ yes  │
+                     │       │ Xeon       │       │        │ (SSD 1024  │       │ A2000 (6   │      │
+                     │       │ Silver     │       │        │ / HDD 0)   │       │ GB VRAM)   │      │
+                     │       │ 4310       │       │        │            │       │            │      │
+                     ╰───────┴────────────┴───────┴────────┴────────────┴───────┴────────────┴──────╯
+                     
+                     """, output);
+                     
+
+        // Describe (strict)
+        (output, yaml) = await ExecuteAsync("servers", "describe", "srv01");
+        Assert.Equal("""
+                    ╭─Server───────────────────────────────╮
+                    │ Name  srv01                          │
+                    │ IPMI  yes                            │
+                    │ RAM   128 GB                         │
+                    │ CPU   Intel Xeon Silver 4310 (12/24) │
+                    ╰──────────────────────────────────────╯
+
+                    """, output);
+                     
+
+        // Tree (loose)
+        (output, yaml) = await ExecuteAsync("servers", "tree", "srv01");
+        Assert.Contains("srv01", output);
+        
+
+        // Delete server
+        (output, yaml) = await ExecuteAsync("servers", "del", "srv01");
+        Assert.Equal("""
+                     Server 'srv01' deleted.
+
+                     """, output);
+    }
+}

+ 0 - 101
Tests/EndToEnd/ServerYamlE2ETests.cs

@@ -1,101 +0,0 @@
-using Tests.EndToEnd.Infra;
-using Xunit.Abstractions;
-
-namespace Tests.EndToEnd;
-
-[Collection("Yaml CLI tests")]
-public class ServerYamlE2ETests(TempYamlCliFixture fs, ITestOutputHelper outputHelper)
-    : IClassFixture<TempYamlCliFixture>
-{
-    private async Task<(string, string)> ExecuteAsync(params string[] args)
-    {
-        outputHelper.WriteLine($"rpk {string.Join(" ", args)}");
-
-        var inputArgs = args.ToArray();
-        var output = await YamlCliTestHost.RunAsync(
-            inputArgs,
-            fs.Root,
-            outputHelper,
-            "config.yaml"
-        );
-
-        outputHelper.WriteLine(output);
-
-        var yaml = await File.ReadAllTextAsync(Path.Combine(fs.Root, "config.yaml"));
-        return (output, yaml);
-    }
-
-    [Fact]
-    public async Task servers_cli_workflow_test()
-    {
-        await File.WriteAllTextAsync(Path.Combine(fs.Root, "config.yaml"), "");
-
-        // Add switch
-        var (output, yaml) = await ExecuteAsync("servers", "add", "node01");
-        Assert.Equal("Server 'node01' added.\n", output);
-        Assert.Contains("name: node01", yaml);
-    }
-
-    [Fact]
-    public async Task servers_tree_cli_workflow_test()
-    {
-        await File.WriteAllTextAsync(Path.Combine(fs.Root, "config.yaml"), "");
-        // Add switch
-        var (output, yaml) = await ExecuteAsync("servers", "add", "node01");
-        Assert.Equal("Server 'node01' added.\n", output);
-        Assert.Contains("name: node01", yaml);
-
-        (output, yaml) = await ExecuteAsync("systems", "add", "host01");
-        Assert.Equal("System 'host01' added.\n", output);
-
-        (output, yaml) = await ExecuteAsync("systems", "add", "host02");
-        Assert.Equal("System 'host02' added.\n", output);
-
-        (output, yaml) = await ExecuteAsync("systems", "add", "host03");
-        Assert.Equal("System 'host03' added.\n", output);
-
-        (output, yaml) = await ExecuteAsync(
-            "systems", "set", "host01",
-            "--runs-on", "node01"
-        );
-        Assert.Equal("System 'host01' updated.\n", output);
-        (output, yaml) = await ExecuteAsync(
-            "systems", "set", "host02",
-            "--runs-on", "node01"
-        );
-        Assert.Equal("System 'host02' updated.\n", output);
-        (output, yaml) = await ExecuteAsync(
-            "systems", "set", "host03",
-            "--runs-on", "node01"
-        );
-        Assert.Equal("System 'host03' updated.\n", output);
-
-
-        (output, yaml) = await ExecuteAsync("services", "add", "immich");
-        Assert.Equal("Service 'immich' added.\n", output);
-
-        (output, yaml) = await ExecuteAsync("services", "add", "paperless");
-        Assert.Equal("Service 'paperless' added.\n", output);
-
-        (output, yaml) = await ExecuteAsync(
-            "services", "set", "immich",
-            "--runs-on", "host01"
-        );
-
-        (output, yaml) = await ExecuteAsync(
-            "services", "set", "paperless",
-            "--runs-on", "host01"
-        );
-
-        (output, yaml) = await ExecuteAsync("servers", "tree", "node01");
-        Assert.Equal("""
-                     node01
-                     ├── System: host01
-                     │   ├── Service: immich
-                     │   └── Service: paperless
-                     ├── System: host02
-                     └── System: host03
-
-                     """, output);
-    }
-}

+ 47 - 0
Tests/EndToEnd/ServiceTests/ServiceCommandTests.cs

@@ -0,0 +1,47 @@
+using Tests.EndToEnd.Infra;
+using Xunit.Abstractions;
+
+namespace Tests.EndToEnd;
+
+[Collection("Yaml CLI tests")]
+public class ServiceCommandTests(TempYamlCliFixture fs, ITestOutputHelper outputHelper)
+    : IClassFixture<TempYamlCliFixture>
+{
+    private async Task<(string output, string yaml)> ExecuteAsync(params string[] args)
+    {
+        var output = await YamlCliTestHost.RunAsync(
+            args,
+            fs.Root,
+            outputHelper,
+            "config.yaml");
+
+        var yaml = await File.ReadAllTextAsync(Path.Combine(fs.Root, "config.yaml"));
+        return (output, yaml);
+    }
+
+    [Fact]
+    public async Task describe_outputs_expected_information()
+    {
+        await ExecuteAsync("services", "add", "svc01");
+        // ToDo Introduce CIDR validation and enforce it in the test 
+        await ExecuteAsync("services", "set", "svc01", "--ip", "1.2.3.4");
+
+        var (output, _) = await ExecuteAsync("services", "describe", "svc01");
+
+        Assert.Contains("svc01", output);
+        Assert.Contains("1.2.3.4", output);
+    }
+
+    [Fact]
+    public async Task help_commands_do_not_throw()
+    {
+        Assert.Contains("Manage services", (await ExecuteAsync("services", "--help")).output);
+        Assert.Contains("Add a new service", (await ExecuteAsync("services", "add", "--help")).output);
+        Assert.Contains("List all services", (await ExecuteAsync("services", "list", "--help")).output);
+        Assert.Contains("Retrieve a service", (await ExecuteAsync("services", "get", "--help")).output);
+        Assert.Contains("Show detailed information", (await ExecuteAsync("services", "describe", "--help")).output);
+        Assert.Contains("Update properties", (await ExecuteAsync("services", "set", "--help")).output);
+        Assert.Contains("Delete a service", (await ExecuteAsync("services", "del", "--help")).output);
+        Assert.Contains("List subnets", (await ExecuteAsync("services", "subnets", "--help")).output);
+    }
+}

+ 63 - 0
Tests/EndToEnd/ServiceTests/ServiceErrorTests.cs

@@ -0,0 +1,63 @@
+using Tests.EndToEnd.Infra;
+using Xunit.Abstractions;
+
+namespace Tests.EndToEnd;
+
+[Collection("Yaml CLI tests")]
+public class ServiceErrorTests(TempYamlCliFixture fs, ITestOutputHelper outputHelper)
+    : IClassFixture<TempYamlCliFixture>
+{
+    private async Task<(string output, string yaml)> ExecuteAsync(params string[] args)
+    {
+        var output = await YamlCliTestHost.RunAsync(
+            args,
+            fs.Root,
+            outputHelper,
+            "config.yaml");
+
+        var yaml = await File.ReadAllTextAsync(Path.Combine(fs.Root, "config.yaml"));
+        return (output, yaml);
+    }
+
+    [Fact]
+    public async Task adding_duplicate_service_returns_error()
+    {
+        await ExecuteAsync("services", "add", "svc01");
+        var (output, _) = await ExecuteAsync("services", "add", "svc01");
+        Assert.Contains("already exists", output, StringComparison.OrdinalIgnoreCase);
+    }
+
+    [Fact]
+    public async Task get_missing_service_returns_error()
+    {
+        var (output, _) = await ExecuteAsync("services", "get", "ghost");
+        Assert.Contains("not found", output, StringComparison.OrdinalIgnoreCase);
+    }
+
+    [Fact]
+    public async Task set_missing_service_returns_error()
+    {
+        var (output, _) = await ExecuteAsync("services", "set", "ghost", "--ip", "1.2.3.4");
+        Assert.Contains("not found", output, StringComparison.OrdinalIgnoreCase);
+    }
+
+    [Fact]
+    public async Task delete_missing_service_returns_error()
+    {
+        var (output, _) = await ExecuteAsync("services", "del", "ghost");
+        Assert.Contains("not found", output, StringComparison.OrdinalIgnoreCase);
+    }
+
+    [Fact]
+    public async Task set_runs_on_missing_system_returns_error()
+    {
+        await ExecuteAsync("services", "add", "svc01");
+
+        var (output, _) = await ExecuteAsync(
+            "services", "set", "svc01",
+            "--runs-on", "ghost"
+        );
+
+        Assert.Contains("not found", output, StringComparison.OrdinalIgnoreCase);
+    }
+}

+ 125 - 0
Tests/EndToEnd/ServiceTests/ServiceWorkflowTests.cs

@@ -0,0 +1,125 @@
+using Tests.EndToEnd.Infra;
+using Xunit.Abstractions;
+
+namespace Tests.EndToEnd;
+
+[Collection("Yaml CLI tests")]
+public class ServiceWorkflowTests(TempYamlCliFixture fs, ITestOutputHelper outputHelper)
+    : IClassFixture<TempYamlCliFixture>
+{
+    private async Task<(string output, string yaml)> ExecuteAsync(params string[] args)
+    {
+        outputHelper.WriteLine($"rpk {string.Join(" ", args)}");
+
+        var output = await YamlCliTestHost.RunAsync(
+            args,
+            fs.Root,
+            outputHelper,
+            "config.yaml");
+
+        outputHelper.WriteLine(output);
+
+        var yaml = await File.ReadAllTextAsync(Path.Combine(fs.Root, "config.yaml"));
+        return (output, yaml);
+    }
+
+    [Fact]
+    public async Task services_cli_workflow_test()
+    {
+        await File.WriteAllTextAsync(Path.Combine(fs.Root, "config.yaml"), "");
+
+        // Add parent system
+        await ExecuteAsync("systems", "add", "sys01");
+
+        // Add service
+        var (output, yaml) = await ExecuteAsync("services", "add", "svc01");
+        Assert.Equal("Service 'svc01' added.\n", output);
+        Assert.Contains("name: svc01", yaml);
+
+        // Update service
+        (output, yaml) = await ExecuteAsync(
+            "services", "set", "svc01",
+            "--ip", "10.0.0.5",
+            "--port", "8080",
+            "--protocol", "http",
+            "--url", "http://10.0.0.5:8080",
+            "--runs-on", "sys01"
+        );
+        Assert.Equal("Service 'svc01' updated.\n", output);
+
+        Assert.Equal("""
+                     version: 1
+                     resources:
+                     - kind: System
+                       name: sys01
+                     - kind: Service
+                       network:
+                         ip: 10.0.0.5
+                         port: 8080
+                         protocol: http
+                         url: http://10.0.0.5:8080
+                       name: svc01
+                       runsOn: sys01
+
+                     """, yaml);
+
+        // Get service
+        (output, yaml) = await ExecuteAsync("services", "get", "svc01");
+        Assert.Equal("svc01  Ip: 10.0.0.5, Port: 8080, Protocol: http, Url: http://10.0.0.5:8080, \nRunsOn: sys01\n", output);
+
+        // List services (strict table)
+        (output, yaml) = await ExecuteAsync("services", "list");
+        Assert.Equal("""
+                     ╭───────┬──────────┬──────┬──────────┬──────────────────────┬─────────╮
+                     │ Name  │ Ip       │ Port │ Protocol │ Url                  │ Runs On │
+                     ├───────┼──────────┼──────┼──────────┼──────────────────────┼─────────┤
+                     │ svc01 │ 10.0.0.5 │ 8080 │ http     │ http://10.0.0.5:8080 │ sys01   │
+                     ╰───────┴──────────┴──────┴──────────┴──────────────────────┴─────────╯
+
+                     """, output);
+
+        // Summary (strict table)
+        (output, yaml) = await ExecuteAsync("services", "summary");
+        Assert.Equal("""
+                     ╭───────┬──────────┬──────┬──────────┬──────────────────────┬─────────╮
+                     │ Name  │ Ip       │ Port │ Protocol │ Url                  │ Runs On │
+                     ├───────┼──────────┼──────┼──────────┼──────────────────────┼─────────┤
+                     │ svc01 │ 10.0.0.5 │ 8080 │ http     │ http://10.0.0.5:8080 │ sys01   │
+                     ╰───────┴──────────┴──────┴──────────┴──────────────────────┴─────────╯
+
+                     """, output);
+
+        // Subnets (strict)
+        (output, yaml) = await ExecuteAsync("services", "subnets");
+        Assert.Equal("""
+                        ╭─────────────┬──────────┬───────────────────────────────────╮
+                        │ Subnet      │ Services │ Utilization                       │
+                        ├─────────────┼──────────┼───────────────────────────────────┤
+                        │ 10.0.0.0/24 │ 1        │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0% │
+                        ╰─────────────┴──────────┴───────────────────────────────────╯
+                        
+                        """, output);
+
+        // Describe (strict)
+        (output, yaml) = await ExecuteAsync("services", "describe", "svc01");
+        Assert.Equal("""
+                     ╭─Service─────────────────────────────────╮
+                     │ Name:      svc01                        │
+                     │ Ip:        10.0.0.5                     │
+                     │ Port:      8080                         │
+                     │ Protocol:  http                         │
+                     │ Url:       http://10.0.0.5:8080         │
+                     │ Runs On:   sys01                        │
+                     ╰─────────────────────────────────────────╯
+                     
+                     """,output);
+                     
+        
+        // Delete service
+        (output, yaml) = await ExecuteAsync("services", "del", "svc01");
+        Assert.Equal("""
+                     Service 'svc01' deleted.
+
+                     """, output);
+    }
+}

+ 0 - 220
Tests/EndToEnd/ServiceYamlE2ETests.cs

@@ -1,220 +0,0 @@
-using Tests.EndToEnd.Infra;
-using Xunit.Abstractions;
-
-namespace Tests.EndToEnd;
-
-[Collection("Yaml CLI tests")]
-public class ServiceYamlE2ETests(TempYamlCliFixture fs, ITestOutputHelper outputHelper)
-    : IClassFixture<TempYamlCliFixture>
-{
-    private async Task<(string, string)> ExecuteAsync(params string[] args)
-    {
-        outputHelper.WriteLine($"rpk {string.Join(" ", args)}");
-
-        var inputArgs = args.ToArray();
-        var output = await YamlCliTestHost.RunAsync(inputArgs, fs.Root, outputHelper, "config.yaml");
-
-        outputHelper.WriteLine(output);
-
-        var yaml = await File.ReadAllTextAsync(Path.Combine(fs.Root, "config.yaml"));
-        return (output, yaml);
-    }
-
-    [Fact]
-    public async Task services_cli_yaml_test()
-    {
-        await File.WriteAllTextAsync(Path.Combine(fs.Root, "config.yaml"), "");
-
-        // Add system
-        var (output, yaml) = await ExecuteAsync("services", "add", "immich");
-        Assert.Equal("Service 'immich' added.\n", output);
-        Assert.Equal("""
-                     version: 1
-                     resources:
-                     - kind: Service
-                       name: immich
-
-                     """, yaml);
-        (output, yaml) = await ExecuteAsync("systems", "add", "vm01");
-
-        // Update system
-        (output, yaml) = await ExecuteAsync("services", "set", "immich", "--ip", "192.168.10.14", "--port", "80",
-            "--protocol", "TCP", "--url", "http://timmoth.lan:80", "--runs-on", "vm01");
-
-        Assert.Equal("Service 'immich' updated.\n", output);
-
-        outputHelper.WriteLine(yaml);
-        Assert.Equal("""
-                     version: 1
-                     resources:
-                     - kind: Service
-                       network:
-                         ip: 192.168.10.14
-                         port: 80
-                         protocol: TCP
-                         url: http://timmoth.lan:80
-                       name: immich
-                       runsOn: vm01
-                     - kind: System
-                       name: vm01
-
-                     """, yaml);
-
-        // Delete system
-        (output, yaml) = await ExecuteAsync("services", "del", "immich");
-        Assert.Equal("""
-                     Service 'immich' deleted.
-
-                     """, output);
-
-        Assert.Equal("""
-                     version: 1
-                     resources:
-                     - kind: System
-                       name: vm01
-
-                     """, yaml);
-
-        // Ensure list is empty
-        (output, yaml) = await ExecuteAsync("services", "list");
-        Assert.Equal("""
-                     No Services found.
-
-                     """, output);
-    }
-
-    [Fact]
-    public async Task services_cli_workflow_test()
-    {
-        await File.WriteAllTextAsync(Path.Combine(fs.Root, "config.yaml"), "");
-
-        // Add system
-        var (output, yaml) = await ExecuteAsync("services", "add", "immich");
-        Assert.Equal("Service 'immich' added.\n", output);
-
-        (output, yaml) = await ExecuteAsync("servers", "add", "c6400");
-        Assert.Equal("Server 'c6400' added.\n", output);
-
-        (output, yaml) = await ExecuteAsync("systems", "add", "vm01");
-        Assert.Equal("System 'vm01' added.\n", output);
-        (output, yaml) = await ExecuteAsync("systems", "set", "vm01", "--runs-on", "c6400");
-
-
-        // Update system
-        (output, yaml) = await ExecuteAsync("services", "set", "immich", "--ip", "192.168.10.14", "--port", "80",
-            "--protocol", "TCP", "--url", "http://timmoth.lan:80", "--runs-on", "vm01");
-
-        Assert.Equal("Service 'immich' updated.\n", output);
-
-        // Get system by name
-        (output, yaml) = await ExecuteAsync("services", "get", "immich");
-        Assert.Equal("""
-                     immich  Ip: 192.168.10.14, Port: 80, Protocol: TCP, Url: http://timmoth.lan:80, 
-                     RunsOn: c6400/vm01
-
-                     """, output);
-
-        // List systems
-        (output, yaml) = await ExecuteAsync("services", "list");
-        Assert.Equal("""
-                     ╭────────┬───────────────┬──────┬──────────┬──────────────────────┬────────────╮
-                     │ Name   │ Ip            │ Port │ Protocol │ Url                  │ Runs On    │
-                     ├────────┼───────────────┼──────┼──────────┼──────────────────────┼────────────┤
-                     │ immich │ 192.168.10.14 │ 80   │ TCP      │ http://timmoth.lan:8 │ c6400/vm01 │
-                     │        │               │      │          │ 0                    │            │
-                     ╰────────┴───────────────┴──────┴──────────┴──────────────────────┴────────────╯
-
-                     """, output);
-
-        // Report systemså
-        (output, yaml) = await ExecuteAsync("services", "summary");
-        Assert.Equal("""
-                     ╭────────┬───────────────┬──────┬──────────┬──────────────────────┬────────────╮
-                     │ Name   │ Ip            │ Port │ Protocol │ Url                  │ Runs On    │
-                     ├────────┼───────────────┼──────┼──────────┼──────────────────────┼────────────┤
-                     │ immich │ 192.168.10.14 │ 80   │ TCP      │ http://timmoth.lan:8 │ c6400/vm01 │
-                     │        │               │      │          │ 0                    │            │
-                     ╰────────┴───────────────┴──────┴──────────┴──────────────────────┴────────────╯
-
-                     """, output);
-
-        // Delete system
-        (output, yaml) = await ExecuteAsync("services", "del", "immich");
-        Assert.Equal("""
-                     Service 'immich' deleted.
-
-                     """, output);
-
-        // Ensure list is empty
-        (output, yaml) = await ExecuteAsync("services", "list");
-        Assert.Equal("""
-                     No Services found.
-
-                     """, output);
-    }
-
-    [Fact]
-    public async Task services_subnets_cli_test()
-    {
-        await File.WriteAllTextAsync(Path.Combine(fs.Root, "config.yaml"), "");
-
-        // Add services
-        var (output, yaml) = await ExecuteAsync("services", "add", "svc1");
-        Assert.Equal("Service 'svc1' added.\n", output);
-
-        (output, yaml) = await ExecuteAsync("services", "add", "svc2");
-        Assert.Equal("Service 'svc2' added.\n", output);
-
-        (output, yaml) = await ExecuteAsync("services", "add", "svc3");
-        Assert.Equal("Service 'svc3' added.\n", output);
-
-        // Add system + server so RunsOn resolves
-        (output, yaml) = await ExecuteAsync("systems", "add", "vm01");
-        Assert.Equal("System 'vm01' added.\n", output);
-
-        (output, yaml) = await ExecuteAsync("servers", "add", "c6400");
-        Assert.Equal("Server 'c6400' added.\n", output);
-
-        (output, yaml) = await ExecuteAsync("systems", "set", "vm01", "--runs-on", "c6400");
-        Assert.Equal("System 'vm01' updated.\n", output);
-
-        // Assign IPs
-        (output, yaml) = await ExecuteAsync("services", "set", "svc1", "--ip", "192.168.10.10", "--port", "80",
-            "--protocol", "TCP", "--runs-on", "vm01");
-        Assert.Equal("Service 'svc1' updated.\n", output);
-
-        (output, yaml) = await ExecuteAsync("services", "set", "svc2", "--ip", "192.168.10.20", "--port", "443",
-            "--protocol", "TCP", "--runs-on", "vm01");
-        Assert.Equal("Service 'svc2' updated.\n", output);
-
-        (output, yaml) = await ExecuteAsync("services", "set", "svc3", "--ip", "10.0.0.5", "--port", "8080",
-            "--protocol", "TCP", "--runs-on", "vm01");
-        Assert.Equal("Service 'svc3' updated.\n", output);
-
-        // -----------------------------
-        // Test CIDR filter mode
-        // -----------------------------
-        (output, yaml) = await ExecuteAsync("services", "subnets", "--cidr", "192.168.10.0/24");
-
-        Assert.Equal("""
-                     Services in 192.168.10.0/24
-                     ╭──────┬───────────────┬─────────╮
-                     │ Name │ IP            │ Runs On │
-                     ├──────┼───────────────┼─────────┤
-                     │ svc1 │ 192.168.10.10 │ vm01    │
-                     │ svc2 │ 192.168.10.20 │ vm01    │
-                     ╰──────┴───────────────┴─────────╯
-
-                     """, output);
-
-        // -----------------------------
-        // Test subnet summary mode
-        // -----------------------------
-        (output, yaml) = await ExecuteAsync("services", "subnets");
-
-        Assert.Contains("Subnet", output);
-        Assert.Contains("Utilization", output);
-        Assert.Contains("192.168.10.0/24", output);
-        Assert.Contains("10.0.0.0/24", output);
-    }
-}

+ 0 - 117
Tests/EndToEnd/SwitchYamlE2ETests.cs

@@ -1,117 +0,0 @@
-using Tests.EndToEnd.Infra;
-using Xunit.Abstractions;
-
-namespace Tests.EndToEnd;
-
-[Collection("Yaml CLI tests")]
-public class SwitchYamlE2ETests(TempYamlCliFixture fs, ITestOutputHelper outputHelper)
-    : IClassFixture<TempYamlCliFixture>
-{
-    private async Task<(string, string)> ExecuteAsync(params string[] args)
-    {
-        outputHelper.WriteLine($"rpk {string.Join(" ", args)}");
-
-        var inputArgs = args.ToArray();
-        var output = await YamlCliTestHost.RunAsync(
-            inputArgs,
-            fs.Root,
-            outputHelper,
-            "config.yaml");
-
-        outputHelper.WriteLine(output);
-
-        var yaml = await File.ReadAllTextAsync(Path.Combine(fs.Root, "config.yaml"));
-        return (output, yaml);
-    }
-
-    [Fact]
-    public async Task switches_cli_workflow_test()
-    {
-        await File.WriteAllTextAsync(Path.Combine(fs.Root, "config.yaml"), "");
-
-        // Add switch
-        var (output, yaml) = await ExecuteAsync("switches", "add", "sw01");
-        Assert.Equal("Switch 'sw01' added.\n", output);
-        Assert.Contains("name: sw01", yaml);
-
-        (output, yaml) = await ExecuteAsync("switches", "set", "sw01", "--Model", "Netgear GS108", "--managed", "true",
-            "--poe", "true");
-        Assert.Equal("Switch 'sw01' updated.\n", output);
-        Assert.Equal("""
-                     version: 1
-                     resources:
-                     - kind: Switch
-                       model: Netgear GS108
-                       managed: true
-                       poe: true
-                       name: sw01
-
-                     """, yaml);
-
-        (output, yaml) = await ExecuteAsync("switches", "add", "sw02");
-        Assert.Equal("Switch 'sw02' added.\n", output);
-        Assert.Contains("name: sw02", yaml);
-
-        (output, yaml) = await ExecuteAsync("switches", "set", "sw02", "--Model", "TP-Link TL-SG108E", "--managed",
-            "false", "--poe", "false");
-        Assert.Equal("Switch 'sw02' updated.\n", output);
-
-        Assert.Equal("""
-                     version: 1
-                     resources:
-                     - kind: Switch
-                       model: Netgear GS108
-                       managed: true
-                       poe: true
-                       name: sw01
-                     - kind: Switch
-                       model: TP-Link TL-SG108E
-                       managed: false
-                       poe: false
-                       name: sw02
-
-                     """, yaml);
-
-        (output, yaml) = await ExecuteAsync("switches", "get", "sw01");
-        Assert.Equal("sw01  Model: Netgear GS108, Managed: Yes, PoE: Yes\n", output);
-
-
-        (output, yaml) = await ExecuteAsync("switches", "list");
-        Assert.Equal("""
-                     ╭──────┬───────────────────┬─────────┬─────┬───────┬──────────────╮
-                     │ Name │ Model             │ Managed │ PoE │ Ports │ Port Summary │
-                     ├──────┼───────────────────┼─────────┼─────┼───────┼──────────────┤
-                     │ sw01 │ Netgear GS108     │ yes     │ yes │ 0     │ Unknown      │
-                     │ sw02 │ TP-Link TL-SG108E │ no      │ no  │ 0     │ Unknown      │
-                     ╰──────┴───────────────────┴─────────┴─────┴───────┴──────────────╯
-
-                     """, output);
-
-        (output, yaml) = await ExecuteAsync("switches", "summary");
-        Assert.Contains("""
-                        ╭──────┬───────────────────┬─────────┬─────┬───────┬───────────┬──────────────╮
-                        │ Name │ Model             │ Managed │ PoE │ Ports │ Max Speed │ Port Summary │
-                        ├──────┼───────────────────┼─────────┼─────┼───────┼───────────┼──────────────┤
-                        │ sw01 │ Netgear GS108     │ yes     │ yes │ 0     │ 0G        │ Unknown      │
-                        │ sw02 │ TP-Link TL-SG108E │ no      │ no  │ 0     │ 0G        │ Unknown      │
-                        ╰──────┴───────────────────┴─────────┴─────┴───────┴───────────┴──────────────╯
-
-                        """, output);
-
-        (output, yaml) = await ExecuteAsync("switches", "del", "sw02");
-        Assert.Equal("""
-                     Switch 'sw02' deleted.
-
-                     """, output);
-
-        (output, yaml) = await ExecuteAsync("switches", "list");
-        Assert.Equal("""
-                     ╭──────┬───────────────┬─────────┬─────┬───────┬──────────────╮
-                     │ Name │ Model         │ Managed │ PoE │ Ports │ Port Summary │
-                     ├──────┼───────────────┼─────────┼─────┼───────┼──────────────┤
-                     │ sw01 │ Netgear GS108 │ yes     │ yes │ 0     │ Unknown      │
-                     ╰──────┴───────────────┴─────────┴─────┴───────┴──────────────╯
-
-                     """, output);
-    }
-}

+ 0 - 152
Tests/EndToEnd/SystemYamlE2ETests.cs

@@ -1,152 +0,0 @@
-using Tests.EndToEnd.Infra;
-using Xunit.Abstractions;
-
-namespace Tests.EndToEnd;
-
-[Collection("Yaml CLI tests")]
-public class SystemYamlE2ETests(TempYamlCliFixture fs, ITestOutputHelper outputHelper)
-    : IClassFixture<TempYamlCliFixture>
-{
-    private async Task<(string, string)> ExecuteAsync(params string[] args)
-    {
-        outputHelper.WriteLine($"rpk {string.Join(" ", args)}");
-
-        var inputArgs = args.ToArray();
-        var output = await YamlCliTestHost.RunAsync(
-            inputArgs,
-            fs.Root,
-            outputHelper,
-            "config.yaml");
-
-        outputHelper.WriteLine(output);
-
-        var yaml = await File.ReadAllTextAsync(Path.Combine(fs.Root, "config.yaml"));
-        return (output, yaml);
-    }
-
-    [Fact]
-    public async Task systems_cli_workflow_test()
-    {
-        await File.WriteAllTextAsync(Path.Combine(fs.Root, "config.yaml"), "");
-
-        var (output, yaml) = await ExecuteAsync("servers", "add", "hypervisor01");
-        (output, yaml) = await ExecuteAsync("systems", "add", "host01");
-        Assert.Equal("System 'host01' added.\n", output);
-        Assert.Equal("""
-                     version: 1
-                     resources:
-                     - kind: Server
-                       name: hypervisor01
-                     - kind: System
-                       name: host01
-
-                     """, yaml);
-
-        // Update system
-        (output, yaml) = await ExecuteAsync(
-            "systems", "set", "host01",
-            "--type", "baremetal",
-            "--os", "ubuntu-22.04",
-            "--cores", "4",
-            "--ram", "8192",
-            "--runs-on", "hypervisor01"
-        );
-
-        Assert.Equal("System 'host01' updated.\n", output);
-
-        outputHelper.WriteLine(yaml);
-        Assert.Equal("""
-                     version: 1
-                     resources:
-                     - kind: Server
-                       name: hypervisor01
-                     - kind: System
-                       type: baremetal
-                       os: ubuntu-22.04
-                       cores: 4
-                       ram: 8192
-                       name: host01
-                       runsOn: hypervisor01
-
-                     """, yaml);
-
-        // Get system by name
-        (output, yaml) = await ExecuteAsync("systems", "get", "host01");
-        Assert.Equal(
-            "host01  Type: baremetal, OS: ubuntu-22.04, Cores: 4, RAM: 8192GB, Storage: 0GB, \nRunsOn: hypervisor01\n",
-            output);
-
-        // List systems
-        (output, yaml) = await ExecuteAsync("systems", "list");
-        Assert.Equal("""
-                     ╭────────┬───────────┬────────────┬───────┬──────────┬────────────┬────────────╮
-                     │ Name   │ Type      │ OS         │ Cores │ RAM (GB) │ Storage    │ Runs On    │
-                     │        │           │            │       │          │ (GB)       │            │
-                     ├────────┼───────────┼────────────┼───────┼──────────┼────────────┼────────────┤
-                     │ host01 │ baremetal │ ubuntu-22. │ 4     │ 8192     │ 0          │ hypervisor │
-                     │        │           │ 04         │       │          │            │ 01         │
-                     ╰────────┴───────────┴────────────┴───────┴──────────┴────────────┴────────────╯
-
-                     """, output);
-
-        // Report systems
-        (output, yaml) = await ExecuteAsync("systems", "summary");
-        Assert.Equal("""
-                     ╭────────┬───────────┬────────────┬───────┬──────────┬────────────┬────────────╮
-                     │ Name   │ Type      │ OS         │ Cores │ RAM (GB) │ Storage    │ Runs On    │
-                     │        │           │            │       │          │ (GB)       │            │
-                     ├────────┼───────────┼────────────┼───────┼──────────┼────────────┼────────────┤
-                     │ host01 │ baremetal │ ubuntu-22. │ 4     │ 8192     │ 0          │ hypervisor │
-                     │        │           │ 04         │       │          │            │ 01         │
-                     ╰────────┴───────────┴────────────┴───────┴──────────┴────────────┴────────────╯
-
-                     """, output);
-
-        // Delete system
-        (output, yaml) = await ExecuteAsync("systems", "del", "host01");
-        Assert.Equal("""
-                     System 'host01' deleted.
-
-                     """, output);
-
-        // Ensure list is empty
-        (output, yaml) = await ExecuteAsync("systems", "list");
-        Assert.Equal("""
-                     No systems found.
-
-                     """, output);
-    }
-
-    [Fact]
-    public async Task system_tree_cli_workflow_test()
-    {
-        await File.WriteAllTextAsync(Path.Combine(fs.Root, "config.yaml"), "");
-
-        var (output, yaml) = await ExecuteAsync("systems", "add", "host01");
-        Assert.Equal("System 'host01' added.\n", output);
-
-        (output, yaml) = await ExecuteAsync("services", "add", "immich");
-        Assert.Equal("Service 'immich' added.\n", output);
-
-        (output, yaml) = await ExecuteAsync("services", "add", "paperless");
-        Assert.Equal("Service 'paperless' added.\n", output);
-
-        (output, yaml) = await ExecuteAsync(
-            "services", "set", "immich",
-            "--runs-on", "host01"
-        );
-
-        (output, yaml) = await ExecuteAsync(
-            "services", "set", "paperless",
-            "--runs-on", "host01"
-        );
-
-        (output, yaml) = await ExecuteAsync("systems", "tree", "host01");
-        Assert.Equal("""
-                     host01
-                     ├── Service: immich
-                     └── Service: paperless
-
-                     """, output);
-    }
-}

+ 0 - 127
Tests/EndToEnd/UpsYamlE2ETests.cs

@@ -1,127 +0,0 @@
-using Tests.EndToEnd.Infra;
-using Xunit.Abstractions;
-
-namespace Tests.EndToEnd;
-
-[Collection("Yaml CLI tests")]
-public class UpsYamlE2ETests(TempYamlCliFixture fs, ITestOutputHelper outputHelper)
-    : IClassFixture<TempYamlCliFixture>
-{
-    private async Task<(string, string)> ExecuteAsync(params string[] args)
-    {
-        outputHelper.WriteLine($"rpk {string.Join(" ", args)}");
-
-        var inputArgs = args.ToArray();
-        var output = await YamlCliTestHost.RunAsync(
-            inputArgs,
-            fs.Root,
-            outputHelper,
-            "config.yaml");
-
-        outputHelper.WriteLine(output);
-
-        var yaml = await File.ReadAllTextAsync(Path.Combine(fs.Root, "config.yaml"));
-        return (output, yaml);
-    }
-
-    [Fact]
-    public async Task ups_cli_workflow_test()
-    {
-        await File.WriteAllTextAsync(Path.Combine(fs.Root, "config.yaml"), "");
-
-        // Add UPS
-        var (output, yaml) = await ExecuteAsync("ups", "add", "ups01");
-        Assert.Equal("UPS 'ups01' added.\n", output);
-        Assert.Contains("name: ups01", yaml);
-
-        // Update UPS
-        (output, yaml) = await ExecuteAsync(
-            "ups", "set", "ups01",
-            "--model", "APC Smart-UPS 1500",
-            "--va", "1500"
-        );
-        Assert.Equal("UPS 'ups01' updated.\n", output);
-
-        Assert.Equal("""
-                     version: 1
-                     resources:
-                     - kind: Ups
-                       model: APC Smart-UPS 1500
-                       va: 1500
-                       name: ups01
-
-                     """, yaml);
-
-        // Add second UPS
-        (output, yaml) = await ExecuteAsync("ups", "add", "ups02");
-        Assert.Equal("UPS 'ups02' added.\n", output);
-        Assert.Contains("name: ups02", yaml);
-
-        (output, yaml) = await ExecuteAsync(
-            "ups", "set", "ups02",
-            "--model", "CyberPower CP1500PFCLCD",
-            "--va", "1500"
-        );
-        Assert.Equal("UPS 'ups02' updated.\n", output);
-
-        Assert.Equal("""
-                     version: 1
-                     resources:
-                     - kind: Ups
-                       model: APC Smart-UPS 1500
-                       va: 1500
-                       name: ups01
-                     - kind: Ups
-                       model: CyberPower CP1500PFCLCD
-                       va: 1500
-                       name: ups02
-
-                     """, yaml);
-
-        // Get UPS
-        (output, yaml) = await ExecuteAsync("ups", "get", "ups01");
-        Assert.Equal("ups01  Model: APC Smart-UPS 1500, VA: 1500\n", output);
-
-        // List UPS units
-        (output, yaml) = await ExecuteAsync("ups", "list");
-        Assert.Equal("""
-                     ╭───────┬─────────────────────────┬──────╮
-                     │ Name  │ Model                   │ VA   │
-                     ├───────┼─────────────────────────┼──────┤
-                     │ ups01 │ APC Smart-UPS 1500      │ 1500 │
-                     │ ups02 │ CyberPower CP1500PFCLCD │ 1500 │
-                     ╰───────┴─────────────────────────┴──────╯
-
-                     """, output);
-
-        // Summary
-        (output, yaml) = await ExecuteAsync("ups", "summary");
-        Assert.Contains("""
-                        ╭───────┬─────────────────────────┬──────╮
-                        │ Name  │ Model                   │ VA   │
-                        ├───────┼─────────────────────────┼──────┤
-                        │ ups01 │ APC Smart-UPS 1500      │ 1500 │
-                        │ ups02 │ CyberPower CP1500PFCLCD │ 1500 │
-                        ╰───────┴─────────────────────────┴──────╯
-
-                        """, output);
-
-        // Delete UPS
-        (output, yaml) = await ExecuteAsync("ups", "del", "ups02");
-        Assert.Equal("""
-                     UPS 'ups02' deleted.
-
-                     """, output);
-
-        // List again
-        (output, yaml) = await ExecuteAsync("ups", "list");
-        Assert.Equal("""
-                     ╭───────┬────────────────────┬──────╮
-                     │ Name  │ Model              │ VA   │
-                     ├───────┼────────────────────┼──────┤
-                     │ ups01 │ APC Smart-UPS 1500 │ 1500 │
-                     ╰───────┴────────────────────┴──────╯
-
-                     """, output);
-    }
-}