From 10de105c13e4ef512fe83b8c1074fc453f3e70ff Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Tue, 1 Jan 2019 22:01:49 +0100 Subject: [PATCH] tests: detect fd leaks on unmount For now, this only prints a message but does not fail the tests. --- tests/defaults/ctlsock_test.go | 7 +++++++ tests/test_helpers/helpers.go | 33 ++++++++++++++++++++++++++++----- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/tests/defaults/ctlsock_test.go b/tests/defaults/ctlsock_test.go index b987bf6..212ded4 100644 --- a/tests/defaults/ctlsock_test.go +++ b/tests/defaults/ctlsock_test.go @@ -4,6 +4,7 @@ import ( "os" "syscall" "testing" + "time" "github.com/rfjakob/gocryptfs/internal/ctlsock" "github.com/rfjakob/gocryptfs/tests/test_helpers" @@ -37,6 +38,9 @@ func TestCtlSock(t *testing.T) { t.Errorf("We should get a warning about non-canonical paths here") } } + // Give the running gocryptfs process a little bit of time to close lingering + // sockets. Avoid triggering the FD leak detector. + time.Sleep(1 * time.Millisecond) } func TestCtlSockDecrypt(t *testing.T) { @@ -87,6 +91,9 @@ func TestCtlSockDecrypt(t *testing.T) { t.Errorf("want=%q got=%q", p, response.Result) } } + // Give the running gocryptfs process a little bit of time to close lingering + // sockets. Avoid triggering the FD leak detector. + time.Sleep(1 * time.Millisecond) } func TestCtlSockDecryptCrash(t *testing.T) { diff --git a/tests/test_helpers/helpers.go b/tests/test_helpers/helpers.go index 22f47b2..1982b96 100644 --- a/tests/test_helpers/helpers.go +++ b/tests/test_helpers/helpers.go @@ -46,8 +46,15 @@ var DefaultPlainDir string // DefaultCipherDir is TmpDir + "/default-cipher" var DefaultCipherDir string -// PID of the running gocryptfs process. Set by Mount(). -var MountPID int +type mountInfo struct { + // PID of the running gocryptfs process. Set by Mount(). + pid int + // List of open FDs of the running gocrypts process. Set by Mount(). + fds []string +} + +// Indexed by mountpoint +var MountInfo map[string]mountInfo // SwitchTMPDIR changes TMPDIR and hence the directory the test are performed in. // This is used when you want to perform tests on a special filesystem. The @@ -63,6 +70,7 @@ func init() { func doInit() { X255 = string(bytes.Repeat([]byte("X"), 255)) + MountInfo = make(map[string]mountInfo) testParentDir := os.TempDir() + "/gocryptfs-test-parent" os.MkdirAll(testParentDir, 0700) @@ -205,7 +213,7 @@ func Mount(c string, p string, showOutput bool, extraArgs ...string) error { if err != nil { return err } - MountPID = cmd.Process.Pid + pid := cmd.Process.Pid // Wait for exit or usr1 go func() { @@ -215,11 +223,13 @@ func Mount(c string, p string, showOutput bool, extraArgs ...string) error { case err := <-chanExit: return err case <-chanUsr1: - return nil + // noop case <-time.After(1 * time.Second): - log.Panicf("Timeout waiting for process %d", MountPID) + log.Panicf("Timeout waiting for process %d", pid) } + // Save PID and open FDs + MountInfo[p] = mountInfo{pid, ListFds(pid)} return nil } @@ -256,6 +266,13 @@ func UnmountPanic(dir string) { // UnmountErr tries to unmount "dir", retrying 10 times, and returns the // resulting error. func UnmountErr(dir string) (err error) { + var fdsNow []string + pid := MountInfo[dir].pid + fds := MountInfo[dir].fds + if pid <= 0 { + fmt.Printf("UnmountErr: %q was not found in MountInfo, cannot check for FD leaks\n", dir) + } + max := 10 // When a new filesystem is mounted, Gnome tries to read files like // .xdg-volume-info, autorun.inf, .Trash. @@ -263,11 +280,17 @@ func UnmountErr(dir string) (err error) { // "Device or resource busy", causing spurious test failures. // Retry a few times to hide that problem. for i := 1; i <= max; i++ { + if pid > 0 { + fdsNow = ListFds(pid) + } cmd := exec.Command(UnmountScript, "-u", dir) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr err = cmd.Run() if err == nil { + if pid > 0 && len(fdsNow) > len(fds) { + fmt.Printf("FD leak? Details:\nold=%v \nnew=%v\n", fds, fdsNow) + } return nil } code := ExtractCmdExitCode(err)