1133aade73
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NKSN3gSg4TKVBBqkwW2djR
123 lines
5.0 KiB
Go
123 lines
5.0 KiB
Go
package web
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"gitea.dooplex.hu/admin/felhom-hub/internal/store"
|
|
)
|
|
|
|
// R-70 card render tests — one per template branch (the v0.70.1 seam-wiring lesson: a
|
|
// conditional affordance ships with a render test per branch of its gate; handler tests prove
|
|
// nothing about reachability). The card replaces the static "delivered to the controller once"
|
|
// copy, so the tests also pin that the old static claim is GONE.
|
|
|
|
func renderConfigFormWith(t *testing.T, delivery *deliveryView) string {
|
|
t.Helper()
|
|
s, _ := newTestServer(t)
|
|
data := configFormView{
|
|
Config: &store.CustomerConfig{CustomerID: "c1"},
|
|
Overrides: map[string]interface{}{
|
|
"offsite": map[string]interface{}{
|
|
"enabled": true, "type": "shared", "host": "u-sub1.example.de",
|
|
"user": "u-sub1", "repo_path": "/home/felhom-repo",
|
|
},
|
|
},
|
|
ActiveNav: "configs",
|
|
Delivery: delivery,
|
|
}
|
|
var b strings.Builder
|
|
if err := s.templates.ExecuteTemplate(&b, "config_form.html", data); err != nil {
|
|
t.Fatalf("render: %v", err)
|
|
}
|
|
return b.String()
|
|
}
|
|
|
|
func TestDeliveryCard_AppliedRenders(t *testing.T) {
|
|
out := renderConfigFormWith(t, &deliveryView{
|
|
State: "applied", Badge: "applied", BadgeClass: "n-ok",
|
|
Line: "offsite active on the box (last report 2 min ago)",
|
|
})
|
|
if !strings.Contains(out, `data-delivery-state="applied"`) || !strings.Contains(out, "offsite active on the box") {
|
|
t.Fatalf("applied state not rendered:\n%s", out)
|
|
}
|
|
if !strings.Contains(out, `class="n n-ok"`) {
|
|
t.Fatal("applied badge must use n-ok")
|
|
}
|
|
if strings.Contains(out, "the transient password is delivered to the controller once") {
|
|
t.Fatal("the old static 'delivered once' claim must be GONE — it hid a burned credential for 2 days (DIAG-f10)")
|
|
}
|
|
}
|
|
|
|
func TestDeliveryCard_ConsumedAwaitingApplyAmberRenders(t *testing.T) {
|
|
out := renderConfigFormWith(t, &deliveryView{
|
|
State: "consumed_awaiting_apply", Badge: "consumed", BadgeClass: "n-warn",
|
|
Line: "password consumed 2.0 h ago and the box still reports no offsite target — likely burned mid-apply; Re-issue delivers a fresh one",
|
|
})
|
|
if !strings.Contains(out, `data-delivery-state="consumed_awaiting_apply"`) ||
|
|
!strings.Contains(out, "likely burned mid-apply") || !strings.Contains(out, `class="n n-warn"`) {
|
|
t.Fatalf("amber consumed_awaiting_apply state not rendered:\n%s", out)
|
|
}
|
|
}
|
|
|
|
func TestDeliveryCard_StagedRenders(t *testing.T) {
|
|
out := renderConfigFormWith(t, &deliveryView{
|
|
State: "staged_awaiting_consume", Badge: "staged", BadgeClass: "n-neutral",
|
|
Line: "one-time password staged 3 min ago — the box consumes it on its next config refresh",
|
|
})
|
|
if !strings.Contains(out, `data-delivery-state="staged_awaiting_consume"`) ||
|
|
!strings.Contains(out, "the box consumes it on its next config refresh") {
|
|
t.Fatalf("staged state not rendered:\n%s", out)
|
|
}
|
|
}
|
|
|
|
// The demo-felhom shape: applied + the stale-staged info line — BOTH must render.
|
|
func TestDeliveryCard_AppliedWithStaleStagedInfoLine(t *testing.T) {
|
|
out := renderConfigFormWith(t, &deliveryView{
|
|
State: "applied", Badge: "applied", BadgeClass: "n-ok",
|
|
Line: "offsite active on the box (last report 2 min ago)",
|
|
StaleLine: "Note: an unconsumed one-time secret has been staged since 2026-07-21 08:29 UTC (2 days ago) — superseded by the working install (key-auth-first never consumes); harmless, replaced by the next re-issue.",
|
|
})
|
|
if !strings.Contains(out, `data-delivery-state="applied"`) ||
|
|
!strings.Contains(out, "an unconsumed one-time secret has been staged since 2026-07-21") {
|
|
t.Fatalf("applied + stale-staged info line not rendered:\n%s", out)
|
|
}
|
|
}
|
|
|
|
// Nil Delivery (brand-new config / detector error): the card is simply absent — never a
|
|
// fabricated state line.
|
|
func TestDeliveryCard_NilDeliveryOmitted(t *testing.T) {
|
|
out := renderConfigFormWith(t, nil)
|
|
if strings.Contains(out, "data-delivery-state") {
|
|
t.Fatalf("nil Delivery must render no state line:\n%s", out)
|
|
}
|
|
// the target line survives (it is descriptor truth, not delivery state)
|
|
if !strings.Contains(out, "u-sub1@u-sub1.example.de:/home/felhom-repo") {
|
|
t.Fatal("provisioned target line must still render")
|
|
}
|
|
}
|
|
|
|
// deliveryViewFor derives from the real detector: the burned shape past 30 min renders amber.
|
|
func TestDeliveryViewFor_BurnedShapeGoesAmber(t *testing.T) {
|
|
s, st := newTestServer(t)
|
|
if err := st.SaveCustomerConfig(&store.CustomerConfig{CustomerID: "c9", APIKey: "k", RetrievalPassword: "p"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := st.SaveOneTimeSecret("c9", "x"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := st.SetOneTimeSecretTimesForTest("c9", "2026-01-01 00:00:00", "2026-01-01 00:03:00"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := st.SaveReport("c9", []byte(`{"health":{"status":"ok"}}`)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
v := s.deliveryViewFor("c9")
|
|
if v == nil || v.State != "consumed_awaiting_apply" || v.BadgeClass != "n-warn" {
|
|
t.Fatalf("view = %+v, want consumed_awaiting_apply with n-warn (amber past 30 min)", v)
|
|
}
|
|
if !strings.Contains(v.Line, "Re-issue") {
|
|
t.Fatalf("amber line must point at the remedy, got %q", v.Line)
|
|
}
|
|
}
|