Files
felhom-controller/controller/internal/stacks/infra_test.go
T
admin abbd9488c6 v0.41.0: first-boot base-infra bring-up + self-heal (+ Section-G mount fix)
New internal/infra package renders traefik/cloudflared/filebrowser from config
(pinned images, single source of truth; web filebrowser path delegates here).
stacks.EnsureBaseStack deploys the traefik-public network + the three stacks,
single-flight + idempotent + non-fatal; wired to first boot and every health
tick. monitor.EffectiveProtected drops cloudflared when no tunnel token.
Section-G fix lives in felhom-agent build-golden.sh (same-path stacks bind).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 14:56:42 +02:00

37 lines
1.1 KiB
Go

package stacks
import (
"io"
"log"
"testing"
"time"
"gitea.dooplex.hu/admin/felhom-controller/internal/config"
)
// TestEnsureBaseStackSingleFlight proves the single-flight guard short-circuits: when infraMu is
// already held, EnsureBaseStack returns immediately (nil) WITHOUT touching docker. We hold the lock
// in this goroutine and call EnsureBaseStack in the same goroutine — Go mutexes are non-reentrant, so
// TryLock fails and the function returns before any docker network/inspect call. If the guard were
// missing, the call would shell out to docker (unavailable in unit tests) and not return nil cleanly.
func TestEnsureBaseStackSingleFlight(t *testing.T) {
m := &Manager{
cfg: &config.Config{},
logger: log.New(io.Discard, "", 0),
}
m.infraMu.Lock()
defer m.infraMu.Unlock()
done := make(chan error, 1)
go func() { done <- m.EnsureBaseStack() }()
select {
case err := <-done:
if err != nil {
t.Fatalf("expected nil (single-flight no-op) while lock held, got %v", err)
}
case <-time.After(3 * time.Second):
t.Fatal("EnsureBaseStack did not short-circuit while infraMu was held (single-flight guard missing?)")
}
}