package web import ( "sync" "testing" "gitea.dooplex.hu/admin/felhom-controller/internal/integrations" ) // TestIntegrationManagerNoRace is a regression test for M25. NewServer launches // the SyncFileBrowserMounts goroutine (which reads s.integrationMgr) from inside // the constructor, BEFORE main.go calls SetIntegrationManager. With a plain // pointer field that write/read pair is a data race; this test reproduces the // concurrent access and must run clean under `go test -race`. // // On the pre-fix code (plain `integrationMgr *integrations.Manager`, written via // `s.integrationMgr = mgr` and read via `s.integrationMgr`) the race detector // flags this. With the atomic.Pointer field it is clean. Run with: // // go test -race ./internal/web/ -run IntegrationManagerNoRace func TestIntegrationManagerNoRace(t *testing.T) { var s Server // zero value: atomic.Pointer field is usable as-is const iters = 2000 var wg sync.WaitGroup // Writer — mirrors main.go calling SetIntegrationManager after construction. wg.Add(1) go func() { defer wg.Done() for i := 0; i < iters; i++ { s.SetIntegrationManager(&integrations.Manager{}) } }() // Reader — mirrors the constructor-launched SyncFileBrowserMounts goroutine // reading the field concurrently with the write above. wg.Add(1) go func() { defer wg.Done() for i := 0; i < iters; i++ { _ = s.integrationMgr.Load() } }() wg.Wait() // And the value round-trips. m := &integrations.Manager{} s.SetIntegrationManager(m) if s.integrationMgr.Load() != m { t.Fatal("SetIntegrationManager/Load round-trip mismatch") } }