package web import ( "net/http" "net/http/httptest" "strings" "testing" "time" "gitea.dooplex.hu/admin/felhom-hub/internal/store" ) // D53 (`08` §10): the „Held apps" list on the host page and on the Hosts page — both branches of each {{if}} rendered // (the seam-wiring rule): a held app shows its app, reason and who may clear it; after the clear, the empty sentence. func TestD53_HeldAppsListOnTheHostPageAndTheHostsPage(t *testing.T) { s, st := newTestServer(t) if err := st.UpsertHost(&store.Host{HostID: "demo-hp-01", CustomerID: "c1", APIKey: "k1"}); err != nil { t.Fatal(err) } now := time.Now() if err := st.UpsertHeldApp("c1", "kimai", "unhealthy_stop", now.Add(-3*24*time.Hour), "stopped by the box for a crash loop", now); err != nil { t.Fatal(err) } render := func() (string, string) { rr := httptest.NewRecorder() s.handleHostsList(rr, httptest.NewRequest(http.MethodGet, "/hosts", nil)) hd := httptest.NewRecorder() s.handleHostDetail(hd, httptest.NewRequest(http.MethodGet, "/hosts/demo-hp-01", nil), "demo-hp-01") if rr.Code != 200 || hd.Code != 200 { t.Fatalf("status: hosts %d, host %d", rr.Code, hd.Code) } return rr.Body.String(), hd.Body.String() } fleet, host := render() for name, body := range map[string]string{"hosts": fleet, "host": host} { if !strings.Contains(body, "Held apps") || !strings.Contains(body, `data-held-app=`) || !strings.Contains(body, "kimai") || !strings.Contains(body, "unhealthy_stop") || !strings.Contains(body, "Start (one more try)") { t.Errorf("%s page: the held app is not listed with its reason and who may clear it", name) } } if !strings.Contains(fleet, `href="/hosts/demo-hp-01#held-apps"`) { t.Error("hosts page: the held app does not link to its host") } if !strings.Contains(host, "stopped by the box for a crash loop") { t.Error("host page: the box's sentence is missing") } if _, err := st.ClearHeldApp("c1", "kimai"); err != nil { t.Fatal(err) } fleet, host = render() if strings.Contains(fleet, `data-held-app=`) || !strings.Contains(fleet, "No app is held on any box.") { t.Error("hosts page: after the clear the list is not empty") } if strings.Contains(host, `data-held-app=`) || !strings.Contains(host, "No app is held on this box.") { t.Error("host page: after the clear the list is not empty") } } // A host with no customer shows no held apps — never the whole fleet's. func TestD53_AHostWithNoCustomerShowsNoHeldApps(t *testing.T) { s, st := newTestServer(t) _ = st.UpsertHeldApp("c9", "x", "restore_failed", time.Now(), "y", time.Now()) if rows := s.hostHeldAppRows("", time.Now()); len(rows) != 0 { t.Fatalf("a customer-less host lists %d held app(s)", len(rows)) } }