package namespace import ( "os" "path/filepath" "strconv" "testing" "git.theodohertyfamily.com/wg-wrap/internal/paths" ) func TestLifecycleReferenceCounting(t *testing.T) { // Use a temporary directory to avoid polluting the system tmpDir := t.TempDir() pm := paths.NewPathManager("", tmpDir) profile := "test-vpn" t.Run("RegisterAndUnregister", func(t *testing.T) { err := RegisterProcess(pm, profile) if err != nil { t.Fatalf("failed to register: %v", err) } pidsDir := GetPidsDirPath(pm, profile) pidFile := filepath.Join(pidsDir, strconv.Itoa(os.Getpid())) if _, err := os.Stat(pidFile); os.IsNotExist(err) { t.Errorf("PID file should exist at %s", pidFile) } err = UnregisterProcess(pm, profile) if err != nil { t.Fatalf("failed to unregister: %v", err) } if _, err := os.Stat(pidFile); err == nil { t.Errorf("PID file should have been removed at %s", pidFile) } }) t.Run("PruneStalePids", func(t *testing.T) { pidsDir := GetPidsDirPath(pm, profile) if err := os.MkdirAll(pidsDir, 0755); err != nil { t.Fatal(err) } fakePid := "9999999" fakePidFile := filepath.Join(pidsDir, fakePid) if err := os.WriteFile(fakePidFile, []byte(""), 0644); err != nil { t.Fatal(err) } if err := RegisterProcess(pm, profile); err != nil { t.Fatal(err) } err := PruneStalePids(pm, profile) if err != nil { t.Fatalf("prune failed: %v", err) } if _, err := os.Stat(fakePidFile); err == nil { t.Errorf("Stale PID file %s should have been pruned", fakePidFile) } currentPidFile := filepath.Join(pidsDir, strconv.Itoa(os.Getpid())) if _, err := os.Stat(currentPidFile); os.IsNotExist(err) { t.Errorf("Current PID file %s should not have been pruned", currentPidFile) } if err := UnregisterProcess(pm, profile); err != nil { t.Fatal(err) } }) t.Run("IsLastProcess", func(t *testing.T) { pidsDir := GetPidsDirPath(pm, profile) if err := os.RemoveAll(pidsDir); err != nil { t.Fatal(err) } isLast, err := IsLastProcess(pm, profile) if err != nil || !isLast { t.Errorf("Expected IsLastProcess to be true for empty profile, got %v, err: %v", isLast, err) } if err := RegisterProcess(pm, profile); err != nil { t.Fatal(err) } isLast, err = IsLastProcess(pm, profile) if err != nil || !isLast { t.Errorf("Expected IsLastProcess to be true for single process, got %v, err: %v", isLast, err) } if err := os.WriteFile(filepath.Join(pidsDir, "1234567"), []byte(""), 0644); err != nil { t.Fatal(err) } isLast, err = IsLastProcess(pm, profile) if err != nil || !isLast { t.Errorf("Expected IsLastProcess to be true because 1234567 is dead, got %v, err: %v", isLast, err) } }) }