Arbeitsstand gesichert: Deploymentcenter-Integration (D-0 bis D-5) und Einfenster-Shell
Sicherungscommit vor dem Aufraeumen des Repos, damit nachvollziehbar bleibt, welcher Stand vor der Bereinigung galt. Build gruen, 476 Tests gruen. Zwei Straenge, die sich ueber .csproj, Program.cs und appsettings.json ueberschneiden und darum gemeinsam abgelegt werden: Deploymentcenter-Integration (P3c, Plan D-0 bis D-5 code-seitig fertig): - Deploymentcenter.Client 2.5.0 als lokales Paket, Source-Mapping erweitert - DeploymentcenterOptions, DeploymentcenterErrorReporter, LicenseGate/LicenseCli - WatchdogHeartbeatService auf die Deploymentcenter-API umgestellt (version, os, checks, metrics, status stopped) - Security: MasterKeyResolver, SecretRedactor, FilePermissions - Directory.Build.props mit zentraler Version 0.1.0 (Packager-Versionsdisziplin) - deploy/: Packager-Vorlage und systemd-Unit; echte Zugangsdaten bleiben ueber .gitignore aussen vor - setup.json fuer die Erstinstallation - UMSETZUNGSPLAN-Deploymentcenter-Integration.md; ANALYSE-Linux-Portierung.md verweist auf den neuen Plan Einfenster-Shell (UI-Redesign): - ShellWindow + ShellNavModel als Seitenleisten-Shell - WindowMenuBar und WindowMenuModel entfallen - Modul- und Kernfenster auf die Shell-Einbettung angepasst Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -29,11 +29,11 @@ namespace PolyTrader.Tests
|
||||
[InlineData("http://127.0.0.1")]
|
||||
public void TryBuildEndpoint_accepts_https_and_local_http(string baseUrl)
|
||||
{
|
||||
bool ok = WatchdogHeartbeatService.TryBuildEndpoint(baseUrl, "heartbeat", out Uri? uri, out string problem);
|
||||
bool ok = WatchdogHeartbeatService.TryBuildEndpoint(baseUrl, WatchdogHeartbeatService.PingPath, out Uri? uri, out string problem);
|
||||
|
||||
Assert.True(ok, problem);
|
||||
Assert.NotNull(uri);
|
||||
Assert.EndsWith("/api/heartbeat", uri!.AbsoluteUri);
|
||||
Assert.EndsWith("/api/watchdog/v1/ping", uri!.AbsoluteUri);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -41,7 +41,7 @@ namespace PolyTrader.Tests
|
||||
{
|
||||
// Über http:// ginge der Agent-Token im Klartext über das Netz.
|
||||
bool ok = WatchdogHeartbeatService.TryBuildEndpoint(
|
||||
"http://watchdog.example.de", "heartbeat", out Uri? uri, out string problem);
|
||||
"http://watchdog.example.de", WatchdogHeartbeatService.PingPath, out Uri? uri, out string problem);
|
||||
|
||||
Assert.False(ok);
|
||||
Assert.Null(uri);
|
||||
@@ -55,7 +55,7 @@ namespace PolyTrader.Tests
|
||||
[InlineData("ftp://watchdog.example.de")]
|
||||
public void TryBuildEndpoint_rejects_invalid_urls(string baseUrl)
|
||||
{
|
||||
bool ok = WatchdogHeartbeatService.TryBuildEndpoint(baseUrl, "heartbeat", out _, out string problem);
|
||||
bool ok = WatchdogHeartbeatService.TryBuildEndpoint(baseUrl, WatchdogHeartbeatService.PingPath, out _, out string problem);
|
||||
|
||||
Assert.False(ok);
|
||||
Assert.NotEmpty(problem);
|
||||
@@ -65,10 +65,10 @@ namespace PolyTrader.Tests
|
||||
public void TryBuildEndpoint_keeps_base_path_of_subdirectory_installs()
|
||||
{
|
||||
bool ok = WatchdogHeartbeatService.TryBuildEndpoint(
|
||||
"https://example.de/watchdog", "heartbeat", out Uri? uri, out _);
|
||||
"https://example.de/watchdog", WatchdogHeartbeatService.PingPath, out Uri? uri, out _);
|
||||
|
||||
Assert.True(ok);
|
||||
Assert.Equal("https://example.de/watchdog/api/heartbeat", uri!.AbsoluteUri);
|
||||
Assert.Equal("https://example.de/watchdog/api/watchdog/v1/ping", uri!.AbsoluteUri);
|
||||
}
|
||||
|
||||
// ----- Konfigurationsprüfung -----
|
||||
@@ -113,8 +113,10 @@ namespace PolyTrader.Tests
|
||||
|
||||
Assert.True(result.Success, result.Detail);
|
||||
Assert.Equal(HttpMethod.Post, handler.LastRequest!.Method);
|
||||
Assert.Equal("https://wd.example.de/api/heartbeat", handler.LastRequest.RequestUri!.AbsoluteUri);
|
||||
Assert.Equal("secret-token", Assert.Single(handler.LastRequest.Headers.GetValues("X-Watchdog-Key")));
|
||||
Assert.Equal("https://wd.example.de/api/watchdog/v1/ping", handler.LastRequest.RequestUri!.AbsoluteUri);
|
||||
Assert.Equal("Bearer", handler.LastRequest.Headers.Authorization!.Scheme);
|
||||
Assert.Equal("secret-token", handler.LastRequest.Headers.Authorization!.Parameter);
|
||||
Assert.False(handler.LastRequest.Headers.Contains("X-Watchdog-Key"));
|
||||
|
||||
using var doc = JsonDocument.Parse(handler.LastBody!);
|
||||
var root = doc.RootElement;
|
||||
@@ -127,6 +129,65 @@ namespace PolyTrader.Tests
|
||||
// Entscheidend: die Watchdog-API liest "interval" und ignoriert "intervalSeconds" still.
|
||||
Assert.Equal(45, root.GetProperty("interval").GetInt32());
|
||||
Assert.False(root.TryGetProperty("intervalSeconds", out _));
|
||||
|
||||
// D-1: Version aus BuildInfo (Directory.Build.props), nicht mehr aus der Assembly-Version.
|
||||
Assert.Equal(PolyTrader.Core.BuildInfo.Version, root.GetProperty("version").GetString());
|
||||
Assert.False(string.IsNullOrWhiteSpace(root.GetProperty("os").GetString()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendHeartbeatAsync_includes_registered_checks()
|
||||
{
|
||||
var service = Build(out FakeHandler handler, Valid());
|
||||
service.RegisterCheck("db", () => (true, null));
|
||||
service.RegisterCheck("market_feed", () => (false, "Letzter Tick vor 14 min"));
|
||||
|
||||
await service.SendHeartbeatAsync();
|
||||
|
||||
using var doc = JsonDocument.Parse(handler.LastBody!);
|
||||
var checks = doc.RootElement.GetProperty("checks");
|
||||
Assert.True(checks.GetProperty("db").GetProperty("ok").GetBoolean());
|
||||
Assert.False(checks.GetProperty("market_feed").GetProperty("ok").GetBoolean());
|
||||
Assert.Equal("Letzter Tick vor 14 min", checks.GetProperty("market_feed").GetProperty("message").GetString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendHeartbeatAsync_omits_checks_when_none_registered()
|
||||
{
|
||||
var service = Build(out FakeHandler handler, Valid());
|
||||
await service.SendHeartbeatAsync();
|
||||
|
||||
using var doc = JsonDocument.Parse(handler.LastBody!);
|
||||
Assert.True(doc.RootElement.TryGetProperty("checks", out var checksProp));
|
||||
Assert.Equal(JsonValueKind.Null, checksProp.ValueKind);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendHeartbeatAsync_check_failure_reports_itself_instead_of_throwing()
|
||||
{
|
||||
var service = Build(out FakeHandler handler, Valid());
|
||||
service.RegisterCheck("boom", () => throw new InvalidOperationException("kaputt"));
|
||||
|
||||
var result = await service.SendHeartbeatAsync();
|
||||
|
||||
Assert.True(result.Success, result.Detail); // die werfende Prüfung darf den Versand nicht verhindern
|
||||
using var doc = JsonDocument.Parse(handler.LastBody!);
|
||||
var boom = doc.RootElement.GetProperty("checks").GetProperty("boom");
|
||||
Assert.False(boom.GetProperty("ok").GetBoolean());
|
||||
Assert.Contains("kaputt", boom.GetProperty("message").GetString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UnregisterCheck_removes_a_previously_registered_check()
|
||||
{
|
||||
var service = Build(out FakeHandler handler, Valid());
|
||||
service.RegisterCheck("temp", () => (true, null));
|
||||
service.UnregisterCheck("temp");
|
||||
|
||||
await service.SendHeartbeatAsync();
|
||||
|
||||
using var doc = JsonDocument.Parse(handler.LastBody!);
|
||||
Assert.Equal(JsonValueKind.Null, doc.RootElement.GetProperty("checks").ValueKind);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -363,7 +424,8 @@ namespace PolyTrader.Tests
|
||||
var result = await service.SendEventAsync("started", "info", "Test");
|
||||
|
||||
Assert.True(result.Success, result.Detail);
|
||||
Assert.Equal("https://wd.example.de/api/event", handler.LastRequest!.RequestUri!.AbsoluteUri);
|
||||
Assert.Equal("https://wd.example.de/api/watchdog/v1/event", handler.LastRequest!.RequestUri!.AbsoluteUri);
|
||||
Assert.Equal("Bearer", handler.LastRequest.Headers.Authorization!.Scheme);
|
||||
using var doc = JsonDocument.Parse(handler.LastBody!);
|
||||
Assert.Equal("started", doc.RootElement.GetProperty("kind").GetString());
|
||||
Assert.Equal("polytrader", doc.RootElement.GetProperty("source").GetString());
|
||||
|
||||
Reference in New Issue
Block a user