diff options
| author | Jakob Unterwurzacher | 2019-01-01 22:01:49 +0100 | 
|---|---|---|
| committer | Jakob Unterwurzacher | 2019-01-01 22:01:49 +0100 | 
| commit | 10de105c13e4ef512fe83b8c1074fc453f3e70ff (patch) | |
| tree | 437c4a1aac2c2050d87ca0c9fbf2d400dc6eadad | |
| parent | cd0ec342b9692c71c50c77caa7b9cfde27426e4d (diff) | |
tests: detect fd leaks on unmount
For now, this only prints a message but does not fail the tests.
| -rw-r--r-- | tests/defaults/ctlsock_test.go | 7 | ||||
| -rw-r--r-- | 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) | 
