feat(installer): pull in preflight check implementations as prerequisite for SystemCheckPage

Git/GitIdentity/Port/WriteAccess and Claude CLI/Version/Auth/PermissionModeAuto
checks plus the ExecutableResolver they depend on were built in two sibling
task branches that hadn't landed on main yet. Vendored the finished files in
from those branches (same content, verified building + tests green) so the
SystemCheckPage task has something to consume.
This commit is contained in:
mika kuns
2026-08-05 19:56:07 +02:00
parent bdee731376
commit 05be07b28c
30 changed files with 1683 additions and 3 deletions
@@ -0,0 +1,68 @@
using System.Net;
using System.Net.Sockets;
using ClaudeDo.Installer.Checks;
using ClaudeDo.Installer.Checks.Interfaces;
using ClaudeDo.Installer.Core;
namespace ClaudeDo.Installer.Tests.Checks;
public sealed class PortCheckTests
{
private sealed class FakeOwnerResolver : IPortOwnerResolver
{
private readonly string? _owner;
public FakeOwnerResolver(string? owner) => _owner = owner;
public Task<string?> FindOwningProcessNameAsync(int port, CancellationToken ct) => Task.FromResult(_owner);
}
private static int GetFreePort()
{
var listener = new TcpListener(IPAddress.Loopback, 0);
listener.Start();
var port = ((IPEndPoint)listener.LocalEndpoint).Port;
listener.Stop();
return port;
}
[Fact]
public async Task Both_ports_free_reports_ok()
{
var ctx = new InstallContext { SignalRPort = GetFreePort(), ExternalMcpPort = GetFreePort() };
var check = new PortCheck(new FakeOwnerResolver(null));
var result = await check.RunAsync(ctx, CancellationToken.None);
Assert.Equal(CheckStatus.Ok, result.Status);
}
[Fact]
public async Task Port_in_use_by_other_process_reports_failed()
{
var port = GetFreePort();
using var occupying = new TcpListener(IPAddress.Loopback, port);
occupying.Start();
var ctx = new InstallContext { SignalRPort = port, ExternalMcpPort = GetFreePort() };
var check = new PortCheck(new FakeOwnerResolver("SomeOtherApp"));
var result = await check.RunAsync(ctx, CancellationToken.None);
Assert.Equal(CheckStatus.Failed, result.Status);
Assert.Equal(CheckSeverity.Warning, result.Severity);
Assert.Contains("SomeOtherApp", result.Message);
}
[Fact]
public async Task Port_in_use_by_own_worker_reports_ok()
{
var port = GetFreePort();
using var occupying = new TcpListener(IPAddress.Loopback, port);
occupying.Start();
var ctx = new InstallContext { SignalRPort = port, ExternalMcpPort = GetFreePort() };
var check = new PortCheck(new FakeOwnerResolver("ClaudeDo.Worker"));
var result = await check.RunAsync(ctx, CancellationToken.None);
Assert.Equal(CheckStatus.Ok, result.Status);
Assert.Contains("ClaudeDo Worker", result.Message);
}
}