daeed175ca
After a guest rebuild the hub (set-only claim, by design) said "Claimed" while the box showed its first-run setup page. The latest report's `claimed` field is now shown; hub-claimed + box-not-claimed renders an amber warning. No claim state is changed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
71 lines
3.0 KiB
Go
71 lines
3.0 KiB
Go
package web
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"gitea.dooplex.hu/admin/felhom-hub/internal/store"
|
|
)
|
|
|
|
// R-283: after a guest rebuild the hub's claim (set-only by design) says "Claimed" while the box serves
|
|
// its first-run setup page. The customer page now shows the BOX's side too, from its latest report, and
|
|
// warns on the mismatch. One render per branch of the template gate (seam rule): unknown, box claimed,
|
|
// box not claimed with an unclaimed hub, and the mismatch.
|
|
// RED-PROOF: drop the ClaimMismatch assignment in configs.go → the mismatch branch assertion fails.
|
|
func TestR283_CustomerPageShowsBoxClaimState(t *testing.T) {
|
|
s, st := newTestServer(t)
|
|
e, _ := withUIClaim(t, s, st)
|
|
cc := &store.CustomerConfig{CustomerID: "acme", CustomerName: "Acme", Domain: "acme.hu",
|
|
RetrievalPassword: "pw", APIKey: "k", Status: "active", Email: "owner@acme.hu"}
|
|
if err := st.SaveCustomerConfig(cc); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := e.EnsureIssued(cc); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// No report at all → unknown.
|
|
html := renderCustomerPage(t, s, "acme")
|
|
if !strings.Contains(html, `id="box-claim-unknown"`) || strings.Contains(html, `id="box-claim-mismatch"`) {
|
|
t.Fatal("no report: want the unknown line and no mismatch")
|
|
}
|
|
// An old controller that does not send the field → still unknown.
|
|
if err := st.SaveReport("acme", []byte(`{"customer_id":"acme"}`)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if html = renderCustomerPage(t, s, "acme"); !strings.Contains(html, `id="box-claim-unknown"`) {
|
|
t.Fatal("a report without the claimed field must read unknown, never not-claimed")
|
|
}
|
|
// Box not claimed, hub not claimed → neutral, no mismatch.
|
|
if err := st.SaveReport("acme", []byte(`{"customer_id":"acme","claimed":false}`)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
html = renderCustomerPage(t, s, "acme")
|
|
if !strings.Contains(html, "Box: not claimed yet") || strings.Contains(html, `id="box-claim-mismatch"`) {
|
|
t.Fatal("unclaimed on both sides: want the neutral box line, no mismatch")
|
|
}
|
|
// Box claims → hub marked claimed; both say claimed.
|
|
if err := e.MarkClaimed(cc); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := st.SaveReport("acme", []byte(`{"customer_id":"acme","claimed":true}`)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
html = renderCustomerPage(t, s, "acme")
|
|
if !strings.Contains(html, "Box: claimed") || strings.Contains(html, `id="box-claim-mismatch"`) {
|
|
t.Fatal("claimed on both sides: want 'Box: claimed', no mismatch")
|
|
}
|
|
// The guest is rebuilt: the box reports claimed=false while the hub keeps its claim → mismatch.
|
|
if err := st.SaveReport("acme", []byte(`{"customer_id":"acme","claimed":false}`)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
html = renderCustomerPage(t, s, "acme")
|
|
if !strings.Contains(html, `id="box-claim-mismatch"`) || !strings.Contains(html, ">Claimed ") {
|
|
t.Fatal("after a rebuild: want the hub's Claimed chip AND the box mismatch warning")
|
|
}
|
|
// Showing it changes nothing: the hub's claim is still set (set-only, by design).
|
|
if cs, _ := st.GetClaim("acme"); cs == nil || cs.ClaimedAt == nil {
|
|
t.Fatal("rendering the page un-claimed the hub")
|
|
}
|
|
}
|