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") } }