diff --git a/tests/Vantage.App.Tests/DockerViewModelTests.cs b/tests/Vantage.App.Tests/DockerViewModelTests.cs new file mode 100644 index 0000000..c788f68 --- /dev/null +++ b/tests/Vantage.App.Tests/DockerViewModelTests.cs @@ -0,0 +1,47 @@ +using Vantage.App.ViewModels; +using Vantage.Core.Docker; +using Vantage.Core.Models; +using Xunit; + +namespace Vantage.App.Tests; + +public class DockerViewModelTests +{ + [Fact] + public async Task RefreshAsync_PopulatesContainersForHost() + { + var viewModel = new DockerViewModel(new MockDockerProvider()); + viewModel.SetHost(new HostConfig { Id = "h1" }); + + await viewModel.RefreshAsync(CancellationToken.None); + + Assert.NotEmpty(viewModel.Containers); + } + + [Fact] + public async Task RefreshAsync_WithoutHostDoesNothing() + { + var viewModel = new DockerViewModel(new MockDockerProvider()); + + await viewModel.RefreshAsync(CancellationToken.None); + + Assert.Empty(viewModel.Containers); + } + + [Fact] + public async Task StopCommand_TransitionsSelectedContainerToExited() + { + var viewModel = new DockerViewModel(new MockDockerProvider()); + viewModel.SetHost(new HostConfig { Id = "h2" }); + await viewModel.RefreshAsync(CancellationToken.None); + + var running = viewModel.Containers.First(c => c.IsRunning); + viewModel.SelectedContainer = running; + + await viewModel.StopCommand.ExecuteAsync(running); + + var reloaded = viewModel.Containers.First(c => c.Id == running.Id); + Assert.Equal(ContainerState.Exited, reloaded.State); + Assert.False(reloaded.IsRunning); + } +} diff --git a/tests/Vantage.App.Tests/MainWindowViewModelTests.cs b/tests/Vantage.App.Tests/MainWindowViewModelTests.cs new file mode 100644 index 0000000..7fae366 --- /dev/null +++ b/tests/Vantage.App.Tests/MainWindowViewModelTests.cs @@ -0,0 +1,70 @@ +using Vantage.App.Tests.Fakes; +using Vantage.App.ViewModels; +using Vantage.Core.Configuration; +using Vantage.Core.Docker; +using Vantage.Core.Health; +using Vantage.Core.Metrics; +using Xunit; + +namespace Vantage.App.Tests; + +public class MainWindowViewModelTests +{ + private static IConfigStore EmptyStore() => + new JsonConfigStore(Path.Combine(Path.GetTempPath(), "vantage-vm-" + Guid.NewGuid().ToString("N"), "config.json")); + + private static MainWindowViewModel Build(IMetricsProvider metrics, IHealthChecker? health = null) => + new(metrics, new MockDockerProvider(), health ?? new HealthChecker(new HttpClient()), EmptyStore()); + + [Fact] + public async Task InitializeAsync_FallsBackToDemoDataWhenConfigEmpty() + { + var viewModel = Build(new MockMetricsProvider()); + + await viewModel.InitializeAsync(); + + Assert.NotEmpty(viewModel.Hosts); + Assert.NotEmpty(viewModel.HealthChecks); + Assert.NotNull(viewModel.SelectedHost); + Assert.Same(viewModel.Hosts[0].Config, viewModel.Docker.Host); + } + + [Fact] + public async Task RefreshSelectedHostAsync_PopulatesMetricsAndHistory() + { + var viewModel = Build(new MockMetricsProvider()); + await viewModel.InitializeAsync(); + + await viewModel.RefreshSelectedHostAsync(CancellationToken.None); + + Assert.True(viewModel.SelectedHost!.IsOnline); + Assert.NotEmpty(viewModel.SelectedHost.CpuPoints); + Assert.StartsWith("Updated", viewModel.StatusLine); + } + + [Fact] + public async Task RefreshSelectedHostAsync_MarksHostUnreachableOnFailure() + { + var viewModel = Build(new ThrowingMetricsProvider()); + await viewModel.InitializeAsync(); + + await viewModel.RefreshSelectedHostAsync(CancellationToken.None); + + Assert.False(viewModel.SelectedHost!.IsOnline); + Assert.Equal(ThrowingMetricsProvider.Message, viewModel.SelectedHost.LastError); + Assert.Contains(ThrowingMetricsProvider.Message, viewModel.StatusLine); + } + + [Fact] + public async Task RunAllHealthAsync_RunsEveryConfiguredCheck() + { + var health = new FakeHealthChecker(Vantage.Core.Models.HealthCheckResult.Up(5, "ok")); + var viewModel = Build(new MockMetricsProvider(), health); + await viewModel.InitializeAsync(); + + await viewModel.RunAllHealthAsync(CancellationToken.None); + + Assert.Equal(viewModel.HealthChecks.Count, health.Calls); + Assert.All(viewModel.HealthChecks, check => Assert.StartsWith("Up", check.StatusText)); + } +} diff --git a/tests/Vantage.App.Tests/ViewModelBindingTests.cs b/tests/Vantage.App.Tests/ViewModelBindingTests.cs new file mode 100644 index 0000000..3c453cc --- /dev/null +++ b/tests/Vantage.App.Tests/ViewModelBindingTests.cs @@ -0,0 +1,62 @@ +using Vantage.App.Tests.Fakes; +using Vantage.App.ViewModels; +using Vantage.Core.Models; +using Xunit; + +namespace Vantage.App.Tests; + +public class ViewModelBindingTests +{ + [Fact] + public void HostViewModel_ApplyMetricsUpdatesTextsAndHistory() + { + var host = new HostViewModel(new HostConfig { Name = "node", Address = "10.0.0.5", Username = "root", Port = 22 }, historyLength: 10); + + host.ApplyMetrics(new HostMetrics + { + CpuUsagePercent = 42.5, + MemoryUsedBytes = 4L * 1024 * 1024 * 1024, + MemoryTotalBytes = 8L * 1024 * 1024 * 1024, + DiskUsedBytes = 50L * 1024 * 1024 * 1024, + DiskTotalBytes = 100L * 1024 * 1024 * 1024, + Load1 = 0.8, + Load5 = 0.6, + Load15 = 0.4, + Uptime = TimeSpan.FromHours(50) + }); + + Assert.Equal(42.5, host.CpuUsagePercent); + Assert.Equal(50.0, host.MemoryUsedPercent); + Assert.Single(host.CpuPoints); + Assert.Equal("4.0 GiB / 8.0 GiB", host.MemoryText); + Assert.True(host.IsOnline); + Assert.Equal("node", host.Name); + Assert.Equal("root@10.0.0.5:22", host.Endpoint); + } + + [Fact] + public void HostViewModel_ApplyErrorMarksOffline() + { + var host = new HostViewModel(new HostConfig { Name = "node" }, historyLength: 10); + + host.ApplyError("connection refused"); + + Assert.False(host.IsOnline); + Assert.Equal("connection refused", host.LastError); + Assert.Equal("Unreachable", host.StatusText); + } + + [Fact] + public async Task HealthCheckViewModel_RunAppliesResult() + { + var config = new HealthCheckConfig { Name = "web", Kind = HealthKind.Http, Target = "https://x" }; + var checker = new FakeHealthChecker(HealthCheckResult.Up(12.4, "HTTP 200 OK")); + var viewModel = new HealthCheckViewModel(config, checker); + + await viewModel.RunCommand.ExecuteAsync(null); + + Assert.Equal(HealthStatus.Up, viewModel.Status); + Assert.StartsWith("Up", viewModel.StatusText); + Assert.Equal("12 ms", viewModel.LatencyText); + } +}