package waf import ( "context" "os" "sync" "testing" "time" "git.netcell-it.de/projekte/edgeguard-native/internal/database" ) // Beweist Fix #15: AlertWriter.Close() flusht, ist idempotent, und Send/Close // racen ohne Panic (Kanal wird nie geschlossen). Guarded per EG_FWTEST_DSN. func TestAlertWriter_CloseFlush(t *testing.T) { dsn := os.Getenv("EG_FWTEST_DSN") if dsn == "" { t.Skip("set EG_FWTEST_DSN to run the alert-writer test") } ctx := context.Background() var mErr error for i := 0; i < 3; i++ { if mErr = database.Migrate(ctx, dsn); mErr == nil { break } time.Sleep(700 * time.Millisecond) } if mErr != nil { t.Fatalf("migrate: %v", mErr) } pool, err := database.Open(ctx, dsn) if err != nil { t.Fatalf("open: %v", err) } defer pool.Close() aw := NewAlertWriter(pool, 64) for i := 0; i < 20; i++ { aw.Send(Alert{Hostname: "t.local", ClientIP: "203.0.113.1", Method: "GET", URI: "/", Action: "detected"}) } // Send parallel zu Close → darf nicht paniken. var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func() { defer wg.Done(); aw.Send(Alert{Hostname: "t.local", Action: "detected"}) }() } done := make(chan struct{}) go func() { aw.Close(); close(done) }() select { case <-done: case <-time.After(10 * time.Second): t.Fatal("Close() did not return (flush hung)") } wg.Wait() // Idempotent + Send nach Close ist No-op (kein Panic). aw.Close() aw.Send(Alert{Hostname: "after.local", Action: "detected"}) }