package http import ( "context" stdhttp "net/http" "strings" "testing" "time" "gitea.dcglab.co.uk/steve/restic-manager/internal/store" ) func getTrend(t *testing.T, baseURL, hostID, rangeKey string, cookie *stdhttp.Cookie) string { t.Helper() client := &stdhttp.Client{ CheckRedirect: func(_ *stdhttp.Request, _ []*stdhttp.Request) error { return stdhttp.ErrUseLastResponse }, } url := baseURL + "/hosts/" + hostID + "/repo/trend" if rangeKey != "" { url += "?range=" + rangeKey } req, err := stdhttp.NewRequest("GET", url, nil) if err != nil { t.Fatalf("new request: %v", err) } req.AddCookie(cookie) res, err := client.Do(req) if err != nil { t.Fatalf("GET %s: %v", url, err) } defer res.Body.Close() if res.StatusCode != stdhttp.StatusOK { t.Fatalf("GET %s: want 200, got %d", url, res.StatusCode) } body := make([]byte, 0, 1<<20) buf := make([]byte, 4096) for { n, rerr := res.Body.Read(buf) body = append(body, buf[:n]...) if rerr != nil { break } } return string(body) } func TestUIRepoTrend_30dRange(t *testing.T) { t.Parallel() _, baseURL, st := newTestServerWithUI(t) cookie := loginAsAdmin(t, st) hostID := makeHost(t, st, "h-trend") ctx := context.Background() now := time.Now().UTC() for i := 0; i < 5; i++ { day := now.AddDate(0, 0, -i).Format("2006-01-02") v := int64(1000 + i*100) c := int64(10 + i) if err := st.UpsertHostRepoStatsHistory(ctx, hostID, day, store.HostRepoStats{TotalSizeBytes: &v, SnapshotCount: &c}, now); err != nil { t.Fatalf("seed %s: %v", day, err) } } body := getTrend(t, baseURL, hostID, "30d", cookie) if !strings.Contains(body, `class="repo-trend-chart"`) { t.Errorf("expected repo-trend-chart SVG in fragment") } if !strings.Contains(body, `id="repo-trend-chart"`) { t.Errorf("expected outer wrapper id=repo-trend-chart") } if !strings.Contains(body, `data-range="30d"`) { t.Errorf("expected data-range=30d") } } func TestUIRepoTrend_InvalidRangeFallsBackTo30d(t *testing.T) { t.Parallel() _, baseURL, st := newTestServerWithUI(t) cookie := loginAsAdmin(t, st) hostID := makeHost(t, st, "h-trend2") body := getTrend(t, baseURL, hostID, "banana", cookie) if !strings.Contains(body, `data-range="30d"`) { t.Errorf("expected data-range=30d on invalid range fallback") } } // TestUIRepoPageRendersTrendPanel — full-page render path: seed 3 // history rows, fetch /hosts/{id}/repo, assert the Trend panel with // SVG chart ID, class, and heading text appear embedded in the page. func TestUIRepoPageRendersTrendPanel(t *testing.T) { t.Parallel() _, baseURL, st := newTestServerWithUI(t) cookie := loginAsAdmin(t, st) hostID := makeHost(t, st, "h-trend-page") ctx := context.Background() now := time.Now().UTC() for i := 0; i < 3; i++ { day := now.AddDate(0, 0, -i).Format("2006-01-02") v := int64(2000 + i*200) c := int64(20 + i) if err := st.UpsertHostRepoStatsHistory(ctx, hostID, day, store.HostRepoStats{TotalSizeBytes: &v, SnapshotCount: &c}, now); err != nil { t.Fatalf("seed %s: %v", day, err) } } body := getRepoPage(t, baseURL, hostID, cookie) if !strings.Contains(body, `id="repo-trend-chart"`) { t.Errorf("expected id=\"repo-trend-chart\" in full-page render") } if !strings.Contains(body, `class="repo-trend-chart"`) { t.Errorf("expected class=\"repo-trend-chart\" in full-page render") } if !strings.Contains(body, ">Trend<") { t.Errorf("expected panel heading '>Trend<' in full-page render") } }