From 7967d8ecd57383f406d202f7e2f65e275bb36fc8 Mon Sep 17 00:00:00 2001 From: Fabricio Voznika Date: Tue, 18 Sep 2018 15:20:19 -0700 Subject: Handle children processes better in tests Reap children more systematically in container tests. Previously, container_test was taking ~5 mins to run because constainer.Destroy() would timeout waiting for the sandbox process to exit. Now the test running in less than a minute. Also made the contract around Container and Sandbox destroy clearer. PiperOrigin-RevId: 213527471 Change-Id: Icca84ee1212bbdcb62bdfc9cc7b71b12c6d1688d --- runsc/test/testutil/testutil.go | 45 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) (limited to 'runsc/test') diff --git a/runsc/test/testutil/testutil.go b/runsc/test/testutil/testutil.go index 4d354de31..2e7f95912 100644 --- a/runsc/test/testutil/testutil.go +++ b/runsc/test/testutil/testutil.go @@ -24,10 +24,10 @@ import ( "net/http" "os" "os/exec" + "os/signal" "path/filepath" "runtime" "syscall" - "testing" "time" "github.com/cenkalti/backoff" @@ -236,10 +236,11 @@ func WaitForHTTP(port int, timeout time.Duration) error { // RunAsRoot ensures the test runs with CAP_SYS_ADMIN. If need it will create // a new user namespace and reexecute the test as root inside of the namespace. -func RunAsRoot(m *testing.M) { +// This functionr returns when it's running as root. If it needs to create +// another process, it will exit from there and not return. +func RunAsRoot() { if specutils.HasCapSysAdmin() { - // Capability: check! Good to run. - os.Exit(m.Run()) + return } // Current process doesn't have CAP_SYS_ADMIN, create user namespace and run @@ -278,3 +279,39 @@ func RunAsRoot(m *testing.M) { } os.Exit(0) } + +// StartReaper starts a gorouting that will reap all children processes created +// by the tests. Caller must call the returned function to stop it. +func StartReaper() func() { + ch := make(chan os.Signal, 1) + signal.Notify(ch, syscall.SIGCHLD) + stop := make(chan struct{}) + + go func() { + for { + select { + case <-ch: + case <-stop: + return + } + for { + cpid, _ := syscall.Wait4(-1, nil, syscall.WNOHANG, nil) + if cpid < 1 { + break + } + } + } + }() + return func() { stop <- struct{}{} } +} + +// RetryEintr retries the function until an error different than EINTR is +// returned. +func RetryEintr(f func() (uintptr, uintptr, error)) (uintptr, uintptr, error) { + for { + r1, r2, err := f() + if err != syscall.EINTR { + return r1, r2, err + } + } +} -- cgit v1.2.3