package e2e import ( "fmt" "os" "os/exec" "path/filepath" "testing" ) // TestResourceExhaustion ensures that repeatedly starting and stopping // tunnels does not leak mounts, file descriptors, or namespaces. func TestResourceExhaustion(t *testing.T) { binaryPath := EnsureBinary(t) tmpRuntimeDir := t.TempDir() tmpConfigDir := t.TempDir() profile := "stress-test" profilesDir := filepath.Join(tmpConfigDir, "wg-wrap", "profiles") if err := os.MkdirAll(profilesDir, 0755); err != nil { t.Fatal(err) } profileConfPath := filepath.Join(profilesDir, profile+".conf") conf := `[Interface] Address = 10.0.0.2/24 PrivateKey = 0000000000000000000000000000000000000000000000000000000000000000 [Peer] PublicKey = 0000000000000000000000000000000000000000000000000000000000000000 AllowedIPs = 0.0.0.0/0 Endpoint = 1.1.1.1:51820 ` if err := os.WriteFile(profileConfPath, []byte(conf), 0644); err != nil { t.Fatal(err) } // We run a burst of short-lived commands to stress the lock and cleanup logic. iterations := 50 for i := 0; i < iterations; i++ { cmd := exec.Command(binaryPath, "--profile", profile, "--", "true") cmd.Env = append(os.Environ(), fmt.Sprintf("XDG_RUNTIME_DIR=%s", tmpRuntimeDir), fmt.Sprintf("XDG_CONFIG_HOME=%s", tmpConfigDir), ) if err := cmd.Run(); err != nil { t.Fatalf("Iteration %d failed: %v", i, err) } } // After all iterations, the pin file should be gone. nsPath := filepath.Join(tmpRuntimeDir, "profiles", profile+".ns") if _, err := os.Stat(nsPath); err == nil { t.Errorf("BUG: Namespace pin file %s still exists after %d iterations", nsPath, iterations) } // PIDs directory should be empty or gone. pidsDir := filepath.Join(tmpRuntimeDir, "profiles", profile, "pids") if files, err := os.ReadDir(pidsDir); err == nil && len(files) > 0 { t.Errorf("BUG: PIDs directory not empty after stress test: %d files remaining", len(files)) } }