//go:build integration package tunnel import ( "context" "encoding/json" "net" "net/http" "os" "sync/atomic" "testing" "time" ) func TestNativeReload(t *testing.T) { nativeLoop(t, false) } func TestNativeRuntime(t *testing.T) { nativeLoop(t, true) } func nativeLoop(t *testing.T, observe bool) { t.Helper() file := os.Getenv("SHORT_RUNTIME") if file == "" { t.Skip("SHORT_RUNTIME requires an isolated native IPsec fixture") } ctx, cancel := context.WithTimeout(context.Background(), 240*time.Second) defer cancel() var ready atomic.Bool var published atomic.Bool if observe { listener, err := net.Listen("tcp", "127.0.0.1:9091") if err != nil { t.Fatal(err) } server := &http.Server{ReadHeaderTimeout: time.Second, Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/status" { http.NotFound(w, r) return } json.NewEncoder(w).Encode(map[string]bool{"ready": ready.Load(), "published": published.Load()}) })} go server.Serve(listener) defer server.Close() } done := make(chan error, 1) go func() { done <- serve(ctx, file, &ready, func(context.Context) error { published.Store(true) return nil }) }() ticker := time.NewTicker(100 * time.Millisecond) defer ticker.Stop() for { select { case err := <-done: t.Fatalf("tunnel ended before fixture completion: %v", err) case <-ctx.Done(): <-done t.Fatal("native fixture did not finish within its bound") case <-ticker.C: if _, err := os.Stat(file + ".done"); err == nil { cancel() if err := <-done; err != nil { t.Fatal(err) } return } } } }