package web import ( "fmt" "io" "log" "strings" "testing" "time" "gitea.dooplex.hu/admin/felhom-controller/internal/config" "gitea.dooplex.hu/admin/felhom-controller/internal/monitor" ) // R-906 — the banner showed „+ 5 további figyelmeztetés" with no warning above it. 9202 (2026-10-08) carried nine // „not on a separate drive" warnings (Inline, PageOnly dashboard/monitoring) and the hub-off warning: the cap took the // first five of all ten, counted five into the overflow line, and the layout then dropped all five visible ones, // because they belong under the storage bars, not in the banner. Every page showed only the overflow line, and the // hub-off warning — the one that DID belong in the banner — was cut. // // RED-PROOF (REPORT-dashboard-layout.md): point baseData and the monitoring handler back at GetAlerts and every page fails // (overflow line present, hub-off banner missing). func TestR906_OverflowCountsOnlyThisPagesBannerAlerts(t *testing.T) { s := newDashboardServer(t, time.Time{}) am := NewAlertManager(log.New(io.Discard, "", 0)) var warnings, kinds []string for i := 0; i < 9; i++ { warnings = append(warnings, fmt.Sprintf("Az adattároló (/mnt/hdd/app%d) nem külön meghajtón van", i)) kinds = append(kinds, monitor.WarnKindStorageNotSeparate) } cfg := &config.Config{} cfg.Hub.Enabled = false // the hub-off warning: the one banner alert this box has cfg.Backup.Enabled = true am.Refresh(&monitor.HealthReport{Status: "warn", Warnings: warnings, WarningKinds: kinds}, cfg, nil, false, "") s.alertManager = am if n := len(am.alerts); n != 10 { t.Fatalf("setup: %d alerts, want 10 (nine inline disk warnings + hub off)", n) } for _, path := range []string{"/launcher", "/stacks", "/backups", "/monitoring", "/launcher?lang=en", "/stacks?lang=en"} { rec := getPage(t, s, path) if rec.Code != 200 { t.Fatalf("GET %s = %d", path, rec.Code) } body := rec.Body.String() if strings.Contains(body, "alert-banner-info") { t.Errorf("%s: an overflow line is shown, but this page shows no more than one banner alert", path) } if got := strings.Count(body, "alert-banner-warning"); got != 1 { t.Errorf("%s: %d warning banners, want 1 (the hub-off warning)", path, got) } } } // The cap still works: six alerts that ALL belong in the banner show five and „+ 1". func TestR906_CapStillCountsBannerAlerts(t *testing.T) { am := NewAlertManager(log.New(io.Discard, "", 0)) var warnings []string for i := 0; i < 5; i++ { warnings = append(warnings, fmt.Sprintf("CPU warning %d", i)) } cfg := &config.Config{} cfg.Hub.Enabled = false cfg.Backup.Enabled = true am.Refresh(&monitor.HealthReport{Status: "warn", Warnings: warnings, WarningKinds: make([]string, 5)}, cfg, nil, false, "") got := am.GetBannerAlerts("launcher", "hu") if len(got) != 6 || got[5].ID != "overflow" || !strings.Contains(got[5].Message, "1") { t.Fatalf("six banner alerts: got %d, last %+v — want five and an overflow of 1", len(got), got[len(got)-1]) } // An Inline/PageOnly alert never enters the banner list, on any page. for _, page := range []string{"dashboard", "monitoring", "launcher"} { for _, a := range am.GetBannerAlerts(page, "hu") { if !bannerShows(a, page) && a.ID != "overflow" { t.Errorf("%s: %q is not a banner alert on this page", page, a.ID) } } } }