package e2e import ( "fmt" "os" "os/exec" "path/filepath" "strings" "testing" ) // TestHostNetworkChange simulates the scenario where the host network state changes // (e.g., interface toggle) while a tunnel is active. // Since we can't easily toggle physical hardware in CI, we verify that the // userspace WireGuard engine can handle connectivity interruptions. func TestHostNetworkChange(t *testing.T) { binaryPath := EnsureBinary(t) tmpRuntimeDir := t.TempDir() tmpConfigDir := t.TempDir() profile := "network-change-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) } // Launch a long-running command to keep the tunnel alive cmd := exec.Command(binaryPath, "run", "--profile", profile, "--", "sleep", "5") cmd.Env = append(os.Environ(), fmt.Sprintf("XDG_RUNTIME_DIR=%s", tmpRuntimeDir), fmt.Sprintf("XDG_CONFIG_HOME=%s", tmpConfigDir), ) if err := cmd.Start(); err != nil { t.Fatalf("Failed to start tunnel: %v", err) } defer func() { _ = cmd.Process.Kill() }() // Wait for the tunnel to be established pidsDir := filepath.Join(tmpRuntimeDir, "profiles", profile, "pids") waitForPids(t, pidsDir, 1) // In a real environment, we would use 'ip link set dev eth0 down' here. // In a test environment, we verify that the userspace WG device is still // operational and hasn't crashed due to the host socket's nature. // We launch a second process to verify the session is still valid. cmdJoin := exec.Command(binaryPath, "run", "--profile", profile, "--", "ls") cmdJoin.Env = append(os.Environ(), fmt.Sprintf("XDG_RUNTIME_DIR=%s", tmpRuntimeDir), fmt.Sprintf("XDG_CONFIG_HOME=%s", tmpConfigDir), "WG_WRAP_VERBOSE=1", ) out, err := cmdJoin.CombinedOutput() if err != nil { t.Fatalf("Joining tunnel failed after simulated host network event: %v\nOutput: %s", err, string(out)) } if !strings.Contains(string(out), "Joining active WireGuard tunnel") { t.Errorf("Expected to join active tunnel, but it was lost. Output: %s", string(out)) } }