1453cfc69b
gates / gates (push) Failing after 50s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
78 lines
3.5 KiB
Go
78 lines
3.5 KiB
Go
package backup
|
|
|
|
import (
|
|
"io/fs"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"syscall"
|
|
"testing"
|
|
|
|
"gitea.dooplex.hu/admin/felhom-controller/internal/settings"
|
|
"gitea.dooplex.hu/admin/felhom-controller/internal/util"
|
|
)
|
|
|
|
// R-362: a data drive unbound 4 s into a scratch restore was reported to the household as
|
|
// „restore dir: mkdir /mnt/felhom-drives/hdd_1/backups: permission denied" — a correct refusal that
|
|
// misdescribed why. The consequence asserted: what the household reads (util.ErrText, the renderer
|
|
// the restore notice uses) names the DRIVE, in both languages, and no longer says "permission
|
|
// denied" — while a genuine permission problem on a drive that IS mounted keeps its own wording.
|
|
func TestR362_DetachedDriveIsNamed(t *testing.T) {
|
|
m, sett := newOffboxManager(t)
|
|
managed := filepath.Join(settings.NetworkMountRoot, "hdd_1")
|
|
legacy := "/mnt/hdd_legacy"
|
|
for _, sp := range []settings.StoragePath{
|
|
{Path: managed, Label: "Kulso HDD"},
|
|
{Path: legacy, Label: "Regi HDD", Disconnected: true},
|
|
} {
|
|
if err := sett.AddStoragePath(sp); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
mounted := false
|
|
m.driveMountedFn = func(string) bool { return mounted }
|
|
eacces := func(p string) error { return &fs.PathError{Op: "mkdir", Path: p, Err: syscall.EACCES} }
|
|
scratch := filepath.Join(managed, "backups", "offsite-restore", "app")
|
|
|
|
// 1. The managed drive is no longer a mount point (the flag has not caught up yet).
|
|
err := m.restoreDirError(scratch, eacces(filepath.Join(managed, "backups")))
|
|
hu, en := util.ErrText("hu", err), util.ErrText("en", err)
|
|
if strings.Contains(hu, "permission denied") || !strings.Contains(hu, "Kulso HDD") || !strings.Contains(hu, "nem érhető el") {
|
|
t.Errorf("R-362: the Hungarian refusal does not name the missing drive: %q", hu)
|
|
}
|
|
if strings.Contains(en, "permission denied") || !strings.Contains(en, "Kulso HDD") || !strings.Contains(en, "cannot be reached") {
|
|
t.Errorf("R-362: the English refusal does not name the missing drive: %q", en)
|
|
}
|
|
|
|
// 2. A legacy path outside the managed parent, flagged disconnected by the drive gate.
|
|
if got := util.ErrText("en", m.restoreDirError(filepath.Join(legacy, "x"), eacces(legacy))); !strings.Contains(got, "Regi HDD") {
|
|
t.Errorf("R-362: a drive the registry marks disconnected is not named: %q", got)
|
|
}
|
|
|
|
// 3. Negative control: the drive IS mounted, so a permission error is a real permission error.
|
|
mounted = true
|
|
if got := util.ErrText("en", m.restoreDirError(scratch, eacces(scratch))); !strings.Contains(got, "permission denied") {
|
|
t.Errorf("a genuine permission error on a mounted drive must keep its wording, got %q", got)
|
|
}
|
|
// 4. Negative control: a different failure class is never re-labelled.
|
|
mounted = false
|
|
if got := util.ErrText("en", m.restoreDirError(scratch, &fs.PathError{Op: "mkdir", Path: scratch, Err: syscall.EIO})); strings.Contains(got, "cannot be reached") {
|
|
t.Errorf("an I/O error was re-labelled as a missing drive: %q", got)
|
|
}
|
|
|
|
// Wiring: every restore that creates its directory goes through restoreDirError — no bare
|
|
// "restore dir: %w" is left at a call site.
|
|
for _, f := range []string{"offbox_restore.go", "offbox.go", "shares_restore.go"} {
|
|
src, rerr := os.ReadFile(f)
|
|
if rerr != nil {
|
|
t.Fatal(rerr)
|
|
}
|
|
if strings.Contains(string(src), `fmt.Errorf("restore dir: %w", err)`) {
|
|
t.Errorf("R-362: %s still returns the raw restore-dir error", f)
|
|
}
|
|
if !strings.Contains(string(src), "m.restoreDirError(") {
|
|
t.Errorf("R-362: %s does not call restoreDirError", f)
|
|
}
|
|
}
|
|
}
|