4
0
Эх сурвалжийг харах

Added basic server commands tests

Tim Jones 2 сар өмнө
parent
commit
89c497f856

+ 1 - 1
RackPeek/Commands/AccessPointReportCommand.cs

@@ -4,7 +4,7 @@ using RackPeek.Domain.Resources.Hardware.Reports;
 using Spectre.Console;
 using Spectre.Console.Cli;
 
-namespace RackPeek;
+namespace RackPeek.Commands;
 
 public class AccessPointReportCommand(
     ILogger<AccessPointReportCommand> logger,

+ 1 - 1
RackPeek/Commands/DesktopReportCommand.cs

@@ -4,7 +4,7 @@ using RackPeek.Domain.Resources.Hardware.Reports;
 using Spectre.Console;
 using Spectre.Console.Cli;
 
-namespace RackPeek;
+namespace RackPeek.Commands;
 
 public class DesktopReportCommand(
     ILogger<DesktopReportCommand> logger,

+ 1 - 1
RackPeek/Commands/ServerCommands.cs

@@ -4,7 +4,7 @@ using RackPeek.Domain.Resources.Hardware.Reports;
 using Spectre.Console;
 using Spectre.Console.Cli;
 
-namespace RackPeek;
+namespace RackPeek.Commands;
 
 public class ServerNameSettings : CommandSettings
 {

+ 1 - 1
RackPeek/Commands/ServerReportCommand.cs

@@ -4,7 +4,7 @@ using RackPeek.Domain.Resources.Hardware.Reports;
 using Spectre.Console;
 using Spectre.Console.Cli;
 
-namespace RackPeek;
+namespace RackPeek.Commands;
 public class ServerReportCommand(ILogger<ServerReportCommand> logger, IServiceProvider serviceProvider)
     : AsyncCommand
 {

+ 1 - 1
RackPeek/Commands/SwitchReportCommand.cs

@@ -4,7 +4,7 @@ using RackPeek.Domain.Resources.Hardware.Reports;
 using Spectre.Console;
 using Spectre.Console.Cli;
 
-namespace RackPeek;
+namespace RackPeek.Commands;
 
 public class SwitchReportCommand(
     ILogger<SwitchReportCommand> logger,

+ 1 - 1
RackPeek/Commands/UpsReportCommand.cs

@@ -4,7 +4,7 @@ using RackPeek.Domain.Resources.Hardware.Reports;
 using Spectre.Console;
 using Spectre.Console.Cli;
 
-namespace RackPeek;
+namespace RackPeek.Commands;
 
 public class UpsReportCommand(
     ILogger<UpsReportCommand> logger,

+ 2 - 0
RackPeek/Program.cs

@@ -4,8 +4,10 @@ using RackPeek.Domain.Resources.Hardware;
 using Spectre.Console;
 using Spectre.Console.Cli;
 using Microsoft.Extensions.Logging;
+using RackPeek.Commands;
 using RackPeek.Domain.Resources.Hardware.Crud;
 using RackPeek.Domain.Resources.Hardware.Reports;
+using RackPeek.Yaml;
 
 namespace RackPeek;
 

+ 1 - 1
RackPeek/Yaml/Converters.cs

@@ -4,7 +4,7 @@ using YamlDotNet.Core;
 using YamlDotNet.Core.Events;
 using YamlDotNet.Serialization;
 
-namespace RackPeek;
+namespace RackPeek.Yaml;
 
 public static class StorageSizeParser
 {

+ 1 - 2
RackPeek/Yaml/YamlHardwareRepository.cs

@@ -1,8 +1,7 @@
-using RackPeek.Domain.Resources;
 using RackPeek.Domain.Resources.Hardware;
 using RackPeek.Domain.Resources.Hardware.Models;
 
-namespace RackPeek;
+namespace RackPeek.Yaml;
 
 public class YamlHardwareRepository : IHardwareRepository
 {

+ 1 - 2
RackPeek/Yaml/YamlResourceCollection.cs

@@ -4,9 +4,8 @@ using RackPeek.Domain.Resources.Hardware.Models;
 using RackPeek.Domain.Resources.SystemResources;
 using YamlDotNet.Serialization;
 using YamlDotNet.Serialization.NamingConventions;
-using YamlDotNet.Helpers;
 
-namespace RackPeek;
+namespace RackPeek.Yaml;
 
 public sealed class YamlResourceCollection
 {

+ 1 - 1
RackPeek/Yaml/YamlSystemRepository.cs

@@ -1,6 +1,6 @@
 using RackPeek.Domain.Resources.SystemResources;
 
-namespace RackPeek;
+namespace RackPeek.Yaml;
 
 public class YamlSystemRepository(YamlResourceCollection resourceCollection) : ISystemRepository
 {

+ 67 - 0
Tests/Hardware/AddServerUseCaseTests.cs

@@ -0,0 +1,67 @@
+using NSubstitute;
+using RackPeek.Domain.Resources.Hardware;
+using RackPeek.Domain.Resources.Hardware.Crud;
+using RackPeek.Domain.Resources.Hardware.Models;
+
+namespace Tests.Hardware;
+
+public class AddServerUseCaseTests
+{
+    [Fact]
+    public async Task ExecuteAsync_Adds_new_server_when_not_exists()
+    {
+        // Arrange
+        var repo = Substitute.For<IHardwareRepository>();
+        repo.GetByNameAsync("node01").Returns((RackPeek.Domain.Resources.Hardware.Models.Hardware?)null);
+
+        var sut = new AddServerUseCase(repo);
+
+        // Act
+        await sut.ExecuteAsync(
+            name: "node01",
+            cpuModel: "Xeon E3",
+            cores: 4,
+            threads: 8,
+            ramGb: 32,
+            ipmi: true
+        );
+
+        // Assert
+        await repo.Received(1).AddAsync(Arg.Is<Server>(s =>
+            s.Name == "node01" &&
+            s.Cpus != null &&
+            s.Cpus.Count == 1 &&
+            s.Cpus[0].Model == "Xeon E3" &&
+            s.Cpus[0].Cores == 4 &&
+            s.Cpus[0].Threads == 8 &&
+            s.Ram.Size == 32 &&
+            s.Ipmi == true
+        ));
+    }
+
+    [Fact]
+    public async Task ExecuteAsync_Throws_if_server_already_exists()
+    {
+        // Arrange
+        var repo = Substitute.For<IHardwareRepository>();
+        repo.GetByNameAsync("node01").Returns(new Server { Name = "node01" });
+
+        var sut = new AddServerUseCase(repo);
+
+        // Act
+        var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () =>
+            await sut.ExecuteAsync(
+                name: "node01",
+                cpuModel: "Xeon E3",
+                cores: 4,
+                threads: 8,
+                ramGb: 32,
+                ipmi: true
+            )
+        );
+
+        // Assert
+        Assert.Equal("Server 'node01' already exists.", ex.Message);
+        await repo.DidNotReceive().AddAsync(Arg.Any<Server>());
+    }
+}

+ 44 - 0
Tests/Hardware/DeleteServerUseCaseTests.cs

@@ -0,0 +1,44 @@
+using NSubstitute;
+using RackPeek.Domain.Resources.Hardware;
+using RackPeek.Domain.Resources.Hardware.Crud;
+using RackPeek.Domain.Resources.Hardware.Models;
+
+namespace Tests.Hardware;
+
+public class DeleteServerUseCaseTests
+{
+    [Fact]
+    public async Task ExecuteAsync_Deletes_server_when_exists()
+    {
+        // Arrange
+        var repo = Substitute.For<IHardwareRepository>();
+        repo.GetByNameAsync("node01").Returns(new Server { Name = "node01" });
+
+        var sut = new DeleteServerUseCase(repo);
+
+        // Act
+        await sut.ExecuteAsync("node01");
+
+        // Assert
+        await repo.Received(1).DeleteAsync("node01");
+    }
+
+    [Fact]
+    public async Task ExecuteAsync_Throws_when_server_not_found()
+    {
+        // Arrange
+        var repo = Substitute.For<IHardwareRepository>();
+        repo.GetByNameAsync("node01").Returns((RackPeek.Domain.Resources.Hardware.Models.Hardware?)null);
+
+        var sut = new DeleteServerUseCase(repo);
+
+        // Act
+        var ex = await Assert.ThrowsAsync<InvalidOperationException>(() =>
+            sut.ExecuteAsync("node01")
+        );
+
+        // Assert
+        Assert.Equal("Server 'node01' not found.", ex.Message);
+        await repo.DidNotReceive().DeleteAsync(Arg.Any<string>());
+    }
+}

+ 68 - 0
Tests/Hardware/DescribeServerUseCaseTests.cs

@@ -0,0 +1,68 @@
+using NSubstitute;
+using RackPeek.Domain.Resources.Hardware;
+using RackPeek.Domain.Resources.Hardware.Crud;
+using RackPeek.Domain.Resources.Hardware.Models;
+
+namespace Tests.Hardware;
+
+public class DescribeServerUseCaseTests
+{
+    [Fact]
+    public async Task ExecuteAsync_Returns_description_when_server_exists()
+    {
+        // Arrange
+        var repo = Substitute.For<IHardwareRepository>();
+        repo.GetByNameAsync("node01").Returns(new Server
+        {
+            Name = "node01",
+            Ipmi = true,
+            Cpus = new()
+            {
+                new Cpu { Model = "Xeon", Cores = 4, Threads = 8 },
+                new Cpu { Model = "Xeon", Cores = 4, Threads = 8 }
+            },
+            Ram = new Ram { Size = 32 },
+            Drives = new()
+            {
+                new Drive { Type = "ssd", Size = 256 },
+                new Drive { Type = "hdd", Size = 2048 }
+            },
+            Nics = new()
+            {
+                new Nic { Speed = 10, Ports = 2 }
+            }
+        });
+
+        var sut = new DescribeServerUseCase(repo);
+
+        // Act
+        var description = await sut.ExecuteAsync("node01");
+
+        // Assert
+        Assert.NotNull(description);
+        Assert.Equal("node01", description!.Name);
+        Assert.Equal("2× Xeon", description.CpuSummary);
+        Assert.Equal(8, description.TotalCores);
+        Assert.Equal(16, description.TotalThreads);
+        Assert.Equal(32, description.RamGb);
+        Assert.Equal(2304, description.TotalStorageGb);
+        Assert.Equal(2, description.NicPorts);
+        Assert.True(description.Ipmi);
+    }
+
+    [Fact]
+    public async Task ExecuteAsync_Returns_null_when_server_not_found()
+    {
+        // Arrange
+        var repo = Substitute.For<IHardwareRepository>();
+        repo.GetByNameAsync("node01").Returns((RackPeek.Domain.Resources.Hardware.Models.Hardware?)null);
+
+        var sut = new DescribeServerUseCase(repo);
+
+        // Act
+        var description = await sut.ExecuteAsync("node01");
+
+        // Assert
+        Assert.Null(description);
+    }
+}

+ 59 - 0
Tests/Hardware/GetServerUseCaseTests.cs

@@ -0,0 +1,59 @@
+using NSubstitute;
+using RackPeek.Domain.Resources.Hardware;
+using RackPeek.Domain.Resources.Hardware.Crud;
+using RackPeek.Domain.Resources.Hardware.Models;
+
+namespace Tests.Hardware;
+
+public class GetServerUseCaseTests
+{
+    [Fact]
+    public async Task ExecuteAsync_Returns_server_when_exists()
+    {
+        // Arrange
+        var repo = Substitute.For<IHardwareRepository>();
+        repo.GetByNameAsync("node01").Returns(new Server { Name = "node01" });
+
+        var sut = new GetServerUseCase(repo);
+
+        // Act
+        var server = await sut.ExecuteAsync("node01");
+
+        // Assert
+        Assert.NotNull(server);
+        Assert.IsType<Server>(server);
+        Assert.Equal("node01", server!.Name);
+    }
+
+    [Fact]
+    public async Task ExecuteAsync_Returns_null_when_not_found()
+    {
+        // Arrange
+        var repo = Substitute.For<IHardwareRepository>();
+        repo.GetByNameAsync("node01").Returns((RackPeek.Domain.Resources.Hardware.Models.Hardware?)null);
+
+        var sut = new GetServerUseCase(repo);
+
+        // Act
+        var server = await sut.ExecuteAsync("node01");
+
+        // Assert
+        Assert.Null(server);
+    }
+
+    [Fact]
+    public async Task ExecuteAsync_Returns_null_when_found_is_not_server()
+    {
+        // Arrange
+        var repo = Substitute.For<IHardwareRepository>();
+        repo.GetByNameAsync("node01").Returns(new Desktop { Name = "desktop1" });
+
+        var sut = new GetServerUseCase(repo);
+
+        // Act
+        var server = await sut.ExecuteAsync("node01");
+
+        // Assert
+        Assert.Null(server);
+    }
+}

+ 52 - 0
Tests/Hardware/GetServersUseCaseTests.cs

@@ -0,0 +1,52 @@
+using NSubstitute;
+using RackPeek.Domain.Resources.Hardware;
+using RackPeek.Domain.Resources.Hardware.Crud;
+using RackPeek.Domain.Resources.Hardware.Models;
+
+namespace Tests.Hardware;
+
+public class GetServersUseCaseTests
+{
+    [Fact]
+    public async Task ExecuteAsync_Returns_only_servers()
+    {
+        // Arrange
+        var repo = Substitute.For<IHardwareRepository>();
+        repo.GetAllAsync().Returns(new List<RackPeek.Domain.Resources.Hardware.Models.Hardware>
+        {
+            new Server { Name = "server1" },
+            new Desktop { Name = "desktop1" },
+            new Server { Name = "server2" }
+        });
+
+        var sut = new GetServersUseCase(repo);
+
+        // Act
+        var servers = await sut.ExecuteAsync();
+
+        // Assert
+        Assert.Equal(2, servers.Count);
+        Assert.All(servers, s => Assert.IsType<Server>(s));
+        Assert.Contains(servers, s => s.Name == "server1");
+        Assert.Contains(servers, s => s.Name == "server2");
+    }
+
+    [Fact]
+    public async Task ExecuteAsync_Returns_empty_when_no_servers()
+    {
+        // Arrange
+        var repo = Substitute.For<IHardwareRepository>();
+        repo.GetAllAsync().Returns(new List<RackPeek.Domain.Resources.Hardware.Models.Hardware>
+        {
+            new Desktop { Name = "desktop1" }
+        });
+
+        var sut = new GetServersUseCase(repo);
+
+        // Act
+        var servers = await sut.ExecuteAsync();
+
+        // Assert
+        Assert.Empty(servers);
+    }
+}

+ 1 - 0
Tests/Hardware/ServerHardwareReportTests.cs

@@ -1,5 +1,6 @@
 using NSubstitute;
 using RackPeek.Domain.Resources.Hardware;
+using RackPeek.Domain.Resources.Hardware.Crud;
 using RackPeek.Domain.Resources.Hardware.Models;
 using RackPeek.Domain.Resources.Hardware.Reports;
 

+ 106 - 0
Tests/Hardware/UpdateServerUseCaseTests.cs

@@ -0,0 +1,106 @@
+using NSubstitute;
+using RackPeek.Domain.Resources.Hardware;
+using RackPeek.Domain.Resources.Hardware.Crud;
+using RackPeek.Domain.Resources.Hardware.Models;
+
+namespace Tests.Hardware;
+
+public class UpdateServerUseCaseTests
+{
+    [Fact]
+    public async Task ExecuteAsync_Updates_ram_ipmi_and_cpu_when_provided()
+    {
+        // Arrange
+        var repo = Substitute.For<IHardwareRepository>();
+        repo.GetByNameAsync("node01").Returns(new Server
+        {
+            Name = "node01",
+            Ipmi = false,
+            Ram = new Ram { Size = 32 },
+            Cpus = new List<Cpu>
+            {
+                new Cpu { Model = "Old", Cores = 2, Threads = 4 }
+            }
+        });
+
+        var sut = new UpdateServerUseCase(repo);
+
+        // Act
+        await sut.ExecuteAsync(
+            name: "node01",
+            ramGb: 64,
+            ipmi: true,
+            cpuModel: "Xeon E3",
+            cores: 4,
+            threads: 8
+        );
+
+        // Assert
+        await repo.Received(1).UpdateAsync(Arg.Is<Server>(s =>
+            s.Name == "node01" &&
+            s.Ram.Size == 64 &&
+            s.Ipmi == true &&
+            s.Cpus != null &&
+            s.Cpus.First().Model == "Xeon E3" &&
+            s.Cpus.First().Cores == 4 &&
+            s.Cpus.First().Threads == 8
+        ));
+    }
+
+    [Fact]
+    public async Task ExecuteAsync_Throws_if_server_not_found()
+    {
+        // Arrange
+        var repo = Substitute.For<IHardwareRepository>();
+        repo.GetByNameAsync("node01").Returns((RackPeek.Domain.Resources.Hardware.Models.Hardware?)null);
+
+        var sut = new UpdateServerUseCase(repo);
+
+        // Act
+        var ex = await Assert.ThrowsAsync<InvalidOperationException>(() =>
+            sut.ExecuteAsync("node01", ramGb: 64)
+        );
+
+        // Assert
+        Assert.Equal("Server 'node01' not found.", ex.Message);
+        await repo.DidNotReceive().UpdateAsync(Arg.Any<Server>());
+    }
+
+    [Fact]
+    public async Task ExecuteAsync_Preserves_existing_values_when_not_provided()
+    {
+        // Arrange
+        var repo = Substitute.For<IHardwareRepository>();
+        repo.GetByNameAsync("node01").Returns(new Server
+        {
+            Name = "node01",
+            Ipmi = false,
+            Ram = new Ram { Size = 32 },
+            Cpus = new List<Cpu>
+            {
+                new Cpu { Model = "Old", Cores = 2, Threads = 4 }
+            }
+        });
+
+        var sut = new UpdateServerUseCase(repo);
+
+        // Act
+        await sut.ExecuteAsync(
+            name: "node01",
+            ramGb: null,
+            ipmi: null,
+            cpuModel: null,
+            cores: null,
+            threads: null
+        );
+
+        // Assert
+        await repo.Received(1).UpdateAsync(Arg.Is<Server>(s =>
+            s.Ram.Size == 32 &&
+            s.Ipmi == false &&
+            s.Cpus.First().Model == "Old" &&
+            s.Cpus.First().Cores == 2 &&
+            s.Cpus.First().Threads == 4
+        ));
+    }
+}

+ 2 - 1
Tests/Yaml/HardwareDeserializationTests.cs

@@ -1,8 +1,9 @@
 using RackPeek;
 using RackPeek.Domain.Resources.Hardware;
 using RackPeek.Domain.Resources.Hardware.Models;
+using RackPeek.Yaml;
 
-namespace Tests;
+namespace Tests.Yaml;
 
 public class HardwareDeserializationTests
 {

+ 2 - 1
Tests/Yaml/SystemDeserializationTests.cs

@@ -1,7 +1,8 @@
 using RackPeek;
 using RackPeek.Domain.Resources.SystemResources;
+using RackPeek.Yaml;
 
-namespace Tests;
+namespace Tests.Yaml;
 
 public class ServiceDeserializationTests
 {