summaryrefslogtreecommitdiffhomepage
path: root/runsc/test/testutil/testutil.go
diff options
context:
space:
mode:
Diffstat (limited to 'runsc/test/testutil/testutil.go')
-rw-r--r--runsc/test/testutil/testutil.go45
1 files changed, 41 insertions, 4 deletions
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
+ }
+ }
+}