فهرست منبع

Merge pull request #16 from Timmoth/Manage-Switch-Through-Cli

Added e2e tests
Tim Jones 2 ماه پیش
والد
کامیت
1c4a90c941

BIN
.DS_Store


+ 21 - 16
RackPeek/Program.cs

@@ -38,7 +38,15 @@ public static class Program
         var registrar = new TypeRegistrar(services);
         var app = new CommandApp(registrar);
         
-        CliBootstrap.BuildApp(app, services, configuration);
+        CliBootstrap.BuildApp(app, services, configuration, [
+            "servers.yaml",
+            "desktops.yaml",
+            "switches.yaml",
+            "ups.yaml",
+            "firewalls.yaml",
+            "laptops.yaml",
+            "routers.yaml"
+        ]);
         
         services.AddLogging(configure =>
             configure
@@ -50,7 +58,12 @@ public static class Program
 
 public static class CliBootstrap
 {
-    public static void BuildApp(CommandApp app, IServiceCollection services, IConfiguration configuration)
+    public static void BuildApp(
+        CommandApp app,
+        IServiceCollection services, 
+        IConfiguration configuration,
+        string[] yamlFiles
+        )
     {
         services.AddSingleton<IConfiguration>(configuration);
 
@@ -60,19 +73,7 @@ public static class CliBootstrap
             var collection = new YamlResourceCollection();
             var basePath = configuration["HardwarePath"] ?? Directory.GetCurrentDirectory();
 
-            collection.LoadFiles(new[]
-            {
-                Path.Combine(basePath, "servers.yaml"),
-                Path.Combine(basePath, "aps.yaml"),
-                Path.Combine(basePath, "desktops.yaml"),
-                Path.Combine(basePath, "switches.yaml"),
-                Path.Combine(basePath, "ups.yaml"),
-                Path.Combine(basePath, "firewalls.yaml"),
-                Path.Combine(basePath, "laptops.yaml"),
-                Path.Combine(basePath, "routers.yaml")
-            });
-
-
+            collection.LoadFiles(yamlFiles.Select(f => Path.Combine(basePath, f)));
             return new YamlHardwareRepository(collection);
         });
 
@@ -138,6 +139,7 @@ public static class CliBootstrap
         services.AddScoped<GetSwitchUseCase>();
         services.AddScoped<GetSwitchesUseCase>();
         services.AddScoped<UpdateSwitchUseCase>();
+        services.AddScoped<DescribeSwitchUseCase>();
 
         // NIC use cases
         services.AddScoped<AddNicUseCase>();
@@ -256,8 +258,11 @@ public static class CliBootstrap
                     server.AddCommand<SwitchAddCommand>("add")
                         .WithDescription("Add a new switch");
 
+                    server.AddCommand<SwitchGetCommand>("list")
+                        .WithDescription("List switches");
+                    
                     server.AddCommand<SwitchGetByNameCommand>("get")
-                        .WithDescription("List switches or get a switches by name");
+                        .WithDescription("Get a switches by name");
 
                     server.AddCommand<SwitchDescribeCommand>("describe")
                         .WithDescription("Show detailed information about a switch");

+ 13 - 20
RackPeek/Yaml/YamlHardwareRepository.cs

@@ -3,66 +3,59 @@ using RackPeek.Domain.Resources.Hardware.Models;
 
 namespace RackPeek.Yaml;
 
-public class YamlHardwareRepository : IHardwareRepository
+public class YamlHardwareRepository(YamlResourceCollection resources) : IHardwareRepository
 {
-    private readonly YamlResourceCollection _resources;
-
-    public YamlHardwareRepository(YamlResourceCollection resources)
-    {
-        _resources = resources;
-    }
-
     public Task<IReadOnlyList<Hardware>> GetAllAsync()
     {
-        return Task.FromResult(_resources.HardwareResources);
+        return Task.FromResult(resources.HardwareResources);
     }
 
     public Task<Hardware?> GetByNameAsync(string name)
     {
-        return Task.FromResult(_resources.GetByName(name) as Hardware);
+        return Task.FromResult(resources.GetByName(name) as Hardware);
     }
 
     public Task AddAsync(Hardware hardware)
     {
-        if (_resources.HardwareResources.Any(r =>
+        if (resources.HardwareResources.Any(r =>
                 r.Name.Equals(hardware.Name, StringComparison.OrdinalIgnoreCase)))
             throw new InvalidOperationException(
                 $"Hardware with name '{hardware.Name}' already exists.");
 
         // Use first file as default for new resources
-        var targetFile = _resources.SourceFiles.FirstOrDefault()
+        var targetFile = resources.SourceFiles.FirstOrDefault()
                          ?? throw new InvalidOperationException("No YAML file loaded.");
 
-        _resources.Add(hardware, targetFile);
-        _resources.SaveAll();
+        resources.Add(hardware, targetFile);
+        resources.SaveAll();
 
         return Task.CompletedTask;
     }
 
     public Task UpdateAsync(Hardware hardware)
     {
-        var existing = _resources.HardwareResources
+        var existing = resources.HardwareResources
             .FirstOrDefault(r => r.Name.Equals(hardware.Name, StringComparison.OrdinalIgnoreCase));
 
         if (existing == null)
             throw new InvalidOperationException($"Hardware '{hardware.Name}' not found.");
 
-        _resources.Update(hardware);
-        _resources.SaveAll();
+        resources.Update(hardware);
+        resources.SaveAll();
 
         return Task.CompletedTask;
     }
 
     public Task DeleteAsync(string name)
     {
-        var existing = _resources.HardwareResources
+        var existing = resources.HardwareResources
             .FirstOrDefault(r => r.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
 
         if (existing == null)
             throw new InvalidOperationException($"Hardware '{name}' not found.");
 
-        _resources.Delete(name);
-        _resources.SaveAll();
+        resources.Delete(name);
+        resources.SaveAll();
 
         return Task.CompletedTask;
     }

+ 2 - 9
Tests/EndToEnd/TempYamlCliFixture.cs → Tests/EndToEnd/Infra/TempYamlCliFixture.cs

@@ -1,4 +1,4 @@
-namespace Tests.EndToEnd;
+namespace Tests.EndToEnd.Infra;
 
 public sealed class TempYamlCliFixture : IAsyncLifetime
 {
@@ -15,14 +15,7 @@ public sealed class TempYamlCliFixture : IAsyncLifetime
         // Create empty YAML files so repo loads cleanly
         foreach (var file in new[]
                  {
-                     "servers.yaml",
-                     "aps.yaml",
-                     "desktops.yaml",
-                     "switches.yaml",
-                     "ups.yaml",
-                     "firewalls.yaml",
-                     "laptops.yaml",
-                     "routers.yaml"
+                     "config.yaml",
                  }) 
         {
             File.WriteAllText(Path.Combine(Root, file), "");

+ 7 - 0
Tests/EndToEnd/Infra/YamlCliTestCollection.cs

@@ -0,0 +1,7 @@
+namespace Tests.EndToEnd.Infra;
+
+[CollectionDefinition("Yaml CLI tests", DisableParallelization = true)]
+public class YamlCliTestCollection
+    : ICollectionFixture<TempYamlCliFixture>
+{
+}

+ 7 - 3
Tests/EndToEnd/YamlCliTestHost.cs → Tests/EndToEnd/Infra/YamlCliTestHost.cs

@@ -3,18 +3,20 @@ using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Logging;
 using RackPeek;
 using RackPeek.Spectre;
+using Spectre.Console;
 using Spectre.Console.Cli;
 using Spectre.Console.Testing;
 using Xunit.Abstractions;
 
-namespace Tests.EndToEnd;
+namespace Tests.EndToEnd.Infra;
 
 public static class YamlCliTestHost
 {
     public static async Task<string> RunAsync(
         string[] args,
         string hardwarePath, 
-        ITestOutputHelper output
+        ITestOutputHelper output,
+        string configFile
     )
     {
         var services = new ServiceCollection();
@@ -30,9 +32,11 @@ public static class YamlCliTestHost
 
         var registrar = new TypeRegistrar(services);
         var app = new CommandApp(registrar);
+        
+        AnsiConsole.Console = console;
         app.Configure(c => c.Settings.Console = console);
         
-        CliBootstrap.BuildApp(app, services, config);
+        CliBootstrap.BuildApp(app, services, config, [configFile]);
         
         services.AddLogging(builder =>
         {

+ 35 - 0
Tests/EndToEnd/ServerYamlE2ETests.cs

@@ -0,0 +1,35 @@
+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()
+    {
+        // Add switch
+        var (output, yaml) = await ExecuteAsync("servers", "add", "node01");
+        Assert.Equal("Server 'node01' added.\n", output);
+        Assert.Contains("name: node01", yaml);
+    }
+}

+ 102 - 7
Tests/EndToEnd/SwitchYamlE2ETests.cs

@@ -1,23 +1,118 @@
+using Tests.EndToEnd.Infra;
 using Xunit.Abstractions;
 
 namespace Tests.EndToEnd;
 
+[Collection("Yaml CLI tests")]
 public class SwitchYamlE2ETests(TempYamlCliFixture fs, ITestOutputHelper outputHelper) : IClassFixture<TempYamlCliFixture>
 {
-    [Fact]
-    public async Task switches_add_writes_to_yaml_file()
+    private async Task<(string, string)> ExecuteAsync(params string[] args)
     {
-        // Act
+        outputHelper.WriteLine($"rpk {string.Join(" ", args)}");
+
+        var inputArgs = args.ToArray();
         var output = await YamlCliTestHost.RunAsync(
-            new[] { "switches", "add", "sw01" },
+            inputArgs,
             fs.Root,
-            outputHelper
+            outputHelper,
+            "config.yaml"
         );
 
         outputHelper.WriteLine(output);
         
-        // Assert
-        var yaml = await File.ReadAllTextAsync(Path.Combine(fs.Root, "servers.yaml"));
+        var yaml = await File.ReadAllTextAsync(Path.Combine(fs.Root, "config.yaml"));
+        return (output, yaml);
+    }
+    
+    [Fact]
+    public async Task switches_cli_workflow_test()
+    {
+        // 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("Server 'sw01' updated.\n", output);
+        Assert.Equal("""
+                     resources:
+                     - kind: Switch
+                       model: Netgear GS108
+                       managed: true
+                       poe: true
+                       ports: 
+                       name: sw01
+                       tags: 
+                     
+                     """, 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("Server 'sw02' updated.\n", output);
+
+        Assert.Equal("""
+                     resources:
+                     - kind: Switch
+                       model: Netgear GS108
+                       managed: true
+                       poe: true
+                       ports: 
+                       name: sw01
+                       tags: 
+                     - kind: Switch
+                       model: TP-Link TL-SG108E
+                       managed: false
+                       poe: false
+                       ports: 
+                       name: sw02
+                       tags: 
+                     
+                     """, 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);
     }
 }