Files

110 lines
4.4 KiB
Go

package web
import (
"context"
"errors"
"io"
"log"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"
"gitea.dooplex.hu/admin/felhom-controller/internal/agentapi"
"gitea.dooplex.hu/admin/felhom-controller/internal/backup"
"gitea.dooplex.hu/admin/felhom-controller/internal/config"
"gitea.dooplex.hu/admin/felhom-controller/internal/settings"
"gitea.dooplex.hu/admin/felhom-controller/internal/stacks"
)
// R-499 — an app on the system disk was told „már szerepelnek a teljes rendszermentésben (PBS)" and
// „nincs külön teendő" on every box, including one whose only whole-system copy sat on the SAME disk
// (measured 2026-09-14). The page must now say what is true for THIS box.
// tier2PageServer builds a real Server with one deployed, driveless app ("privatebin") and the
// agent's tier/disk answers injected through the production seams, then renders the real handler.
func tier2PageServer(t *testing.T, tiers func(context.Context) (agentapi.TiersResponse, error), disks []agentapi.DiskInfo) string {
t.Helper()
lg := log.New(io.Discard, "", 0)
dir := t.TempDir()
cfg := &config.Config{}
cfg.Paths.StacksDir = filepath.Join(dir, "stacks")
cfg.Paths.DataDir = filepath.Join(dir, "data")
cfg.Paths.SystemDataPath = filepath.Join(dir, "system")
cfg.Stacks.ComposeCommand = "docker compose"
cfg.Backup.Enabled = true
app := filepath.Join(cfg.Paths.StacksDir, "privatebin")
if err := os.MkdirAll(app, 0o755); err != nil {
t.Fatal(err)
}
os.WriteFile(filepath.Join(app, "docker-compose.yml"), []byte("services:\n privatebin:\n image: privatebin/pdo:2.0.6\n"), 0o644)
os.WriteFile(filepath.Join(app, "app.yaml"), []byte("deployed: true\n"), 0o600)
sett, err := settings.Load(filepath.Join(dir, "settings.json"), lg)
if err != nil {
t.Fatal(err)
}
sm, err := stacks.NewManager(cfg, lg)
if err != nil {
t.Fatal(err)
}
if err := sm.ScanStacks(); err != nil {
t.Fatal(err)
}
bm := backup.NewManager(cfg, sett, lg)
bm.SetStackProvider(&blockProvider{hdd: ""}) // driveless: IsHDDApp false
s := &Server{cfg: cfg, settings: sett, stackMgr: sm, backupMgr: bm, logger: lg, version: "test"}
s.tiersFn = tiers
s.disksFn = func(context.Context) (agentapi.DisksResponse, error) {
return agentapi.DisksResponse{Disks: disks}, nil
}
s.loadTemplates()
w := httptest.NewRecorder()
s.tier2ConfigPageHandler(w, httptest.NewRequest("GET", "/stacks/privatebin/backup", nil), "privatebin")
if w.Code != 200 {
t.Fatalf("page answered %d", w.Code)
}
return w.Body.String()
}
func primaryTier(target string) func(context.Context) (agentapi.TiersResponse, error) {
return func(context.Context) (agentapi.TiersResponse, error) {
return agentapi.TiersResponse{Tiers: []agentapi.BackupTierInfo{{Target: target, Primary: true}}}, nil
}
}
// COMPANION RED-PROOF: rendering the old sentence for every branch (the pre-fix template) makes the
// same_disk case fail on `promises the backup protects this app`.
func TestR499_Tier2PageSaysWhatIsTrueForThisBox(t *testing.T) {
ownDrive := agentapi.DiskInfo{Name: "mentes", MountPath: "/mnt/mentes", GuestPath: "/mnt/felhom-drives/mentes", Role: "user-data", BackupTarget: true}
cases := []struct {
name, want string
tiers func(context.Context) (agentapi.TiersResponse, error)
disks []agentapi.DiskInfo
}{
{"same disk (the measured box)", "same_disk", primaryTier("local"), nil},
{"own drive", "protected", primaryTier("felhom-backup"), []agentapi.DiskInfo{ownDrive}},
{"configured drive gone", "absent", primaryTier("felhom-backup"), nil},
{"agent not askable", "unknown", func(context.Context) (agentapi.TiersResponse, error) {
return agentapi.TiersResponse{}, errors.New("down")
}, nil},
}
for _, c := range cases {
body := tier2PageServer(t, c.tiers, c.disks)
if !strings.Contains(body, `data-system-backup="`+c.want+`"`) {
t.Errorf("%s: want branch %q on the page", c.name, c.want)
}
// ASCII fragments (ui-hungarian rule): "(PBS)" and "nincs k" of „nincs külön teendő".
if strings.Contains(body, "(PBS)") {
t.Errorf("%s: the page still names PBS, which this box may not have", c.name)
}
promises := strings.Contains(body, "nincs k")
if c.want == "protected" && !promises {
t.Errorf("%s: control — the protected branch must still say there is nothing to do", c.name)
}
if c.want != "protected" && promises {
t.Errorf("%s: promises the backup protects this app (\"nothing to do\") on a box where it may not", c.name)
}
}
}