package web import ( "strings" "testing" "gitea.dooplex.hu/admin/felhom-controller/internal/config" ) // T1: agentClient() must return the SAME *agentapi.Client across calls — one Client ⇒ one pooled // http.Transport ⇒ the per-call Transport leak (idle ESTABLISHED sockets to the agent's :8443 that // exhausted the ephemeral port range after ~5 days) is structurally impossible. cfg.LocalAPI is // valid-but-non-network (agentapi.New builds the struct without dialing), so this is hermetic. // // Companion red-proof: reverting agentClient() to `return agentapi.New(...)` makes the two pointers // differ → this test fails (demonstrated, then reverted, during implementation). func TestAgentClient_ReusesSameInstance(t *testing.T) { s := &Server{cfg: &config.Config{LocalAPI: config.LocalAPIConfig{ Endpoint: "127.0.0.1:8443", Token: "tok", Fingerprint: strings.Repeat("a", 64), // syntactically valid 64-hex; no network touched }}} c1, err := s.agentClient() if err != nil { t.Fatalf("agentClient() #1: %v", err) } c2, err := s.agentClient() if err != nil { t.Fatalf("agentClient() #2: %v", err) } if c1 == nil || c2 == nil { t.Fatal("agentClient() returned a nil client") } if c1 != c2 { t.Fatalf("agentClient() must return the SAME instance (leak fix); got %p then %p", c1, c2) } } // T1b: the "not configured" semantics are preserved — an empty endpoint still errors, OUTSIDE the // memoizing Once (so an unprovisioned guest never caches a client). func TestAgentClient_UnconfiguredErrors(t *testing.T) { s := &Server{cfg: &config.Config{}} // LocalAPI.Endpoint == "" if _, err := s.agentClient(); err == nil { t.Fatal("expected an 'agent not configured' error when Endpoint is empty") } }