98 lines
4.0 KiB
Go
98 lines
4.0 KiB
Go
package web
|
|
|
|
import (
|
|
"io"
|
|
"log"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"syscall"
|
|
"testing"
|
|
|
|
"gitea.dooplex.hu/admin/felhom-controller/internal/backup"
|
|
"gitea.dooplex.hu/admin/felhom-controller/internal/config"
|
|
"gitea.dooplex.hu/admin/felhom-controller/internal/settings"
|
|
)
|
|
|
|
// D25 (operator ruling 2026-10-21): the restore page lists kept second-drive copies with „Eltávolítás" — and shows no
|
|
// section at all when there are none. Render test per branch of the {{if .KeptCopies}} gate (the seam-wiring rule).
|
|
func TestD25_RestorePageListsKeptCopiesWithRemove(t *testing.T) {
|
|
base := func() map[string]interface{} {
|
|
d := i18nLayoutData("backups-restore", "Visszaállítás a mentésből")
|
|
d["Backup"] = i18nBackupStatus(false, false)
|
|
d["OffboxConfigured"] = true
|
|
d["OffsiteStoreState"] = "known"
|
|
return d
|
|
}
|
|
with := base()
|
|
with["KeptCopies"] = []keptCopyRow{{ID: "0123456789abcdef", Source: "csaladi_fotok", Line: "a(z) hdd_3 meghajtóról megőrzött másolat · a meghajtó nincs csatlakoztatva", SizeHuman: "1.2 GB", Since: "2026-10-21T12:00:00Z"}}
|
|
html := renderBackupPage(t, "backups_restore", with)
|
|
for _, want := range []string{"Megőrzött másolatok", "csaladi_fotok", "a(z) hdd_3 meghajtóról megőrzött másolat", `action="/backup/kept/remove"`,
|
|
`name="id" value="0123456789abcdef"`, `name="confirm" value="1"`, "Eltávolítás", "confirmRemoveKeptCopy(this)"} {
|
|
if !strings.Contains(html, want) {
|
|
t.Errorf("restore page with a kept copy lacks %q", want)
|
|
}
|
|
}
|
|
if html := renderBackupPage(t, "backups_restore", base()); strings.Contains(html, "Megőrzött másolatok") || strings.Contains(html, "/backup/kept/remove") {
|
|
t.Error("restore page with NO kept copy shows the kept-copies section")
|
|
}
|
|
}
|
|
|
|
// „Eltávolítás" through the handler: no confirm → refused, nothing removed; an unknown id → its own refusal; the
|
|
// recorded copy → removed, and ONLY it. Real settings + manager + disk (the record is the only selector).
|
|
func TestD25_RemoveHandlerRemovesOnlyTheRecordedCopy(t *testing.T) {
|
|
tmp := t.TempDir()
|
|
lg := log.New(io.Discard, "", 0)
|
|
sett, err := settings.Load(filepath.Join(tmp, "settings.json"), lg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
destBase := filepath.Join(tmp, "hdd_1", "backups", "secondary", "_shares")
|
|
kept := filepath.Join(destBase, "hdd_3", "csaladi_fotok")
|
|
other := filepath.Join(destBase, "hdd_2", "b_share")
|
|
for _, d := range []string{kept, other} {
|
|
if err := os.MkdirAll(d, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(d, "f.txt"), []byte("x"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
st, _ := os.Stat(kept)
|
|
sys := st.Sys().(*syscall.Stat_t)
|
|
if err := sett.UpsertKeptCopy(settings.KeptCopy{Kind: "share", Source: "csaladi_fotok", Drive: "hdd_3", Reason: "drive_away",
|
|
DestBase: destBase, Path: kept, Dev: uint64(sys.Dev), Ino: sys.Ino}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
id := settings.KeptCopyID(kept)
|
|
cfg := &config.Config{}
|
|
cfg.Paths.DataDir = tmp
|
|
s := &Server{cfg: cfg, backupMgr: backup.NewManager(cfg, sett, lg), logger: lg}
|
|
post := func(form string) string {
|
|
rr := httptest.NewRecorder()
|
|
req := httptest.NewRequest("POST", "/backup/kept/remove", strings.NewReader(form))
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
s.keptCopyRemoveHandler(rr, req)
|
|
return rr.Header().Get("Location")
|
|
}
|
|
if loc := post("id=" + id); !strings.Contains(loc, "flash.kept.needs_confirmation") {
|
|
t.Fatalf("no confirm → %q", loc)
|
|
}
|
|
if _, err := os.Stat(kept); err != nil {
|
|
t.Fatal("removed without a confirm")
|
|
}
|
|
if loc := post("id=ffffffffffffffff&confirm=1"); !strings.Contains(loc, "flash.kept.not_found") {
|
|
t.Fatalf("unknown id → %q", loc)
|
|
}
|
|
if loc := post("id=" + id + "&confirm=1"); !strings.Contains(loc, "flash.kept.removed") {
|
|
t.Fatalf("recorded copy → %q", loc)
|
|
}
|
|
if _, err := os.Stat(kept); !os.IsNotExist(err) {
|
|
t.Fatalf("the kept copy is still there: %v", err)
|
|
}
|
|
if _, err := os.Stat(filepath.Join(other, "f.txt")); err != nil {
|
|
t.Fatalf("another copy was touched: %v", err)
|
|
}
|
|
}
|