Files
felhom-controller/controller/internal/web/netprobe_stub_test.go
T
admin c0f3e12483 v0.117.0: consuming-namespace NAS verification + deploy-view truth (RCA fixes 2+4)
statfs fsclass helper (network/autofs/stub/unknown, fail-open); probe not_network_fs
assertion (stub can never verify — red-proven); deploy-time stub refusal (idle autofs
proceeds — red-proven); distinct stub badge, stub wins over unreachable (unreachable line
byte-identical); deployed select shows stored HDD_PATH (red-proven vs IsDefault-only).
MinAgent unchanged 0.81.0. Gates green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
2026-07-11 21:12:48 +02:00

99 lines
3.9 KiB
Go

package web
import (
"context"
"os"
"runtime"
"strings"
"testing"
"gitea.dooplex.hu/admin/felhom-controller/internal/agentapi"
"gitea.dooplex.hu/admin/felhom-controller/internal/system"
)
// The stub trap (RCA fix 2): a probe dir that is NOT a mounted network filesystem must exit
// not-network-fs — writability alone can never verify a share again. Seam-modeled (cross-platform);
// the real-statfs leg is TestNetProbeChild_RealLocalDirRefused below.
// Companion red-proof: remove the fstype assertion from NetProbeChild → this expects exit 5 but
// gets 0 (the stub VERIFIES) → FAIL — the exact regression this task exists to prevent.
func TestNetProbeChild_StubRefused(t *testing.T) {
orig := netProbeFSClass
t.Cleanup(func() { netProbeFSClass = orig })
netProbeFSClass = func(string) string { return system.FSClassStub }
dir := t.TempDir()
if got := NetProbeChild(dir); got != netProbeExitNotNetFS {
t.Fatalf("probe against a stub dir: exit = %d, want %d (not_network_fs)", got, netProbeExitNotNetFS)
}
// The probe file must not linger after the refusal.
entries, err := os.ReadDir(dir)
if err != nil {
t.Fatal(err)
}
if len(entries) != 0 {
t.Errorf("probe file not cleaned up after stub refusal: %v", entries)
}
}
// After a create, an AUTOFS answer means the mount did not materialize — mounted network forms
// only pass the child (idle-trigger tolerance belongs to the deploy gate, not the probe).
func TestNetProbeChild_AutofsAfterCreateRefused(t *testing.T) {
orig := netProbeFSClass
t.Cleanup(func() { netProbeFSClass = orig })
netProbeFSClass = func(string) string { return system.FSClassAutofs }
if got := NetProbeChild(t.TempDir()); got != netProbeExitNotNetFS {
t.Fatalf("autofs-after-create: exit = %d, want %d", got, netProbeExitNotNetFS)
}
}
// Real-IO (linux): the platform classifier against a plain local dir — no seam. THE state the RCA
// remediation left behind must never verify again.
func TestNetProbeChild_RealLocalDirRefused(t *testing.T) {
if runtime.GOOS != "linux" {
t.Skip("statfs f_type is linux-only; exercised on the Linux build server")
}
if got := NetProbeChild(t.TempDir()); got != netProbeExitNotNetFS {
t.Fatalf("real local dir: exit = %d, want %d (the stub verified!)", got, netProbeExitNotNetFS)
}
}
// The parent verdict map: exit 5 → failed category not_network_fs.
func TestNetProbeVerdict_NotNetworkFS(t *testing.T) {
o := netProbeVerdict(netProbeExitNotNetFS, "detail")
if o.OK || o.Category != "not_network_fs" {
t.Fatalf("verdict = %+v, want !OK + not_network_fs", o)
}
}
// Job-level: a stub probe verdict rolls the agent install back, registers NOTHING, and surfaces the
// §3.2 Hungarian message for not_network_fs.
func TestNetAdd_StubProbe_RollsBackNotRegistered(t *testing.T) {
s := testServer(t)
agent := &fakeNetAgent{addRes: okAddRes("media"), verify: agentapi.NetVerifyStatus{Phase: "done", JobID: "job-1"}}
s.netProbeFn = func(_ context.Context, _ string) probeOutcome {
// The real chain: child exit → verdict (the seam models the stub without a real mount).
orig := netProbeFSClass
defer func() { netProbeFSClass = orig }()
netProbeFSClass = func(string) string { return system.FSClassStub }
return netProbeVerdict(NetProbeChild(t.TempDir()), "")
}
if !s.startNetAdd(agent, netAddReq("media"), "NAS media") {
t.Fatal("startNetAdd refused")
}
job := waitNetAdd(t, s)
if job.Phase != netAddPhaseFailed || job.Category != "not_network_fs" {
t.Fatalf("phase/category = %s/%s, want failed/not_network_fs", job.Phase, job.Category)
}
if !strings.Contains(job.Message, "nem jött létre megfelelően") {
t.Errorf("not_network_fs Hungarian message missing, got %q", job.Message)
}
if got := agent.removed(); len(got) != 1 || got[0] != "media" {
t.Errorf("stub probe must roll the agent install back: removes=%v", got)
}
if got := networkPathCount(s); got != 0 {
t.Errorf("a stub share must NOT be registered (got %d paths)", got)
}
}