summaryrefslogtreecommitdiff
path: root/nslcd_systemd/misc_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'nslcd_systemd/misc_test.go')
-rw-r--r--nslcd_systemd/misc_test.go176
1 files changed, 104 insertions, 72 deletions
diff --git a/nslcd_systemd/misc_test.go b/nslcd_systemd/misc_test.go
index a910cd9..8ef697a 100644
--- a/nslcd_systemd/misc_test.go
+++ b/nslcd_systemd/misc_test.go
@@ -22,6 +22,7 @@ import (
"io/ioutil"
"net"
"os"
+ "runtime"
"strings"
"sync"
"syscall"
@@ -34,13 +35,39 @@ import (
"golang.org/x/sys/unix"
)
+func init() {
+ if fdIsDevNull(3) == nil {
+ return
+ }
+
+ devnull, err := os.OpenFile("/dev/null", os.O_RDWR, 0666)
+ if err != nil {
+ panic(err)
+ }
+ if devnull.Fd() == 3 {
+ return
+ }
+
+ fmt.Fprintln(os.Stderr, "Could not open /dev/null on FD 3; calling dup2 and re-exec()ing")
+ // shell out to do the FD manipulation--If we made it here,
+ // there's a good chance that FD3 was managed by the go
+ // runtime, and would be changed before we execve(2).
+ panic(syscall.Exec("/bin/sh", append([]string{"sh", "-c", "exec -- \"$@\" 3<>/dev/null"}, os.Args...), os.Environ()))
+}
+
type testContext struct {
*testing.T
tmpdir string
status chan<- string
}
-func testBadClient(t *testContext, backend nslcd_systemd.Backend, toclose bool) {
+func testDriver(
+ t *testContext,
+ backend nslcd_systemd.Backend,
+ limits nslcd_server.Limits,
+ notifyHandler func(dat []byte, oob []byte) error,
+ client func(sockname string)) {
+
t.status <- "setting up"
errfatal := func(err error) {
@@ -51,72 +78,31 @@ func testBadClient(t *testContext, backend nslcd_systemd.Backend, toclose bool)
evExitSupervisor := make(chan error)
evExitServer := make(chan uint8)
- evReload := make(chan bool)
// supervisor //////////////////////////////////////////////////////////
notify_sock, err := sdNotifyListen(t.tmpdir + "/notify.sock")
errfatal(err)
go func() {
- reloading := false
- evExitSupervisor <- sdNotifyHandle(notify_sock, func(dat []byte, oob []byte) error {
- for _, line := range strings.Split(string(dat), "\n") {
- switch line {
- case "RELOADING=1":
- reloading = true
- case "READY=1":
- if reloading {
- evReload <- true
- }
- reloading = false
- }
- }
- return nil
- })
+ evExitSupervisor <- sdNotifyHandle(notify_sock, notifyHandler)
}()
// server //////////////////////////////////////////////////////////////
errfatal(sdActivatedStream(t.tmpdir + "/nslcd.sock"))
go func() {
- evExitServer <- nslcd_systemd.Main(backend, nslcd_server.Limits{
- Timeout: 1 * time.Second,
- })
+ evExitServer <- nslcd_systemd.Main(backend, limits)
}()
// client/driver ///////////////////////////////////////////////////////
+ t.status <- "running client"
+ client(t.tmpdir + "/nslcd.sock")
- t.status <- "talking with server"
- conn, err := net.Dial("unix", t.tmpdir+"/nslcd.sock")
- errfatal(err)
- errfatal(nslcd_proto.Write(conn, nslcd_proto.NSLCD_VERSION))
- errfatal(nslcd_proto.Write(conn, nslcd_proto.NSLCD_ACTION_PASSWD_ALL))
- // Wait for NSLCD_RESULT_*, to make sure the server has made
- // it in to backend code.
- var n int32
- errfatal(nslcd_proto.Read(conn, &n))
- if n != nslcd_proto.NSLCD_VERSION {
- t.Fatal("server version wrong")
- }
- errfatal(nslcd_proto.Read(conn, &n))
- if n != nslcd_proto.NSLCD_ACTION_PASSWD_ALL {
- t.Fatal("server action wrong")
- }
- errfatal(nslcd_proto.Read(conn, &n))
- if n != nslcd_proto.NSLCD_RESULT_BEGIN && n != nslcd_proto.NSLCD_RESULT_END {
- t.Fatal("server result malformed")
- }
- if toclose {
- errfatal(conn.Close())
- }
-
- t.status <- "waiting for server reload"
- errfatal(unix.Kill(unix.Getpid(), unix.SIGHUP))
- <-evReload
+ // exit ////////////////////////////////////////////////////////////////
// A limitation of Unix sockets is that some may get dropped
// if they arrive close together. So give it some (a half
// second is probably generous by a couple orders of
- // magnitude) time to handle SIGHUP before sending SIGTERM, so
- // that we are sure it gets both.
+ // magnitude) time between the client sending any signals and
+ // us sending SIGTERM, so that we are sure it gets both.
time.Sleep(time.Second / 2)
t.status <- "waiting for server exit"
@@ -136,6 +122,9 @@ func testBadClient(t *testContext, backend nslcd_systemd.Backend, toclose bool)
errfatal(notify_sock.Close())
}
+func testClientHang(t *testContext, backend nslcd_systemd.Backend, toclose bool) {
+}
+
type NonLockingBackend struct {
nslcd_server.NilBackend
}
@@ -203,27 +192,7 @@ func (o *LockingBackend) Passwd_All(cred unix.Ucred, req nslcd_proto.Request_Pas
return ret
}
-func init() {
- if fdIsDevNull(3) == nil {
- return
- }
-
- devnull, err := os.OpenFile("/dev/null", os.O_RDWR, 0666)
- if err != nil {
- panic(err)
- }
- if devnull.Fd() == 3 {
- return
- }
-
- fmt.Fprintln(os.Stderr, "Could not open /dev/null on FD 3; calling dup2 and re-exec()ing")
- // shell out to do the FD manipulation--If we made it here,
- // there's a good chance that FD3 was managed by the go
- // runtime, and would be changed before we execve(2).
- panic(syscall.Exec("/bin/sh", append([]string{"sh", "-c", "exec -- \"$@\" 3<>/dev/null"}, os.Args...), os.Environ()))
-}
-
-func TestBadClient(t *testing.T) {
+func TestClientHang(t *testing.T) {
testcases := []struct {
name string
backend nslcd_systemd.Backend
@@ -236,7 +205,7 @@ func TestBadClient(t *testing.T) {
}
for _, testcase := range testcases {
func() {
- tmpdir, err := ioutil.TempDir("", "go-test-libnslcd-bad-client.")
+ tmpdir, err := ioutil.TempDir("", "go-test-libnslcd-client-hang.")
if err != nil {
t.Fatal(err)
}
@@ -245,7 +214,70 @@ func TestBadClient(t *testing.T) {
t.Run(testcase.name, func(t *testing.T) {
testWithTimeout(t, 2*time.Second, func(t *testing.T, s chan<- string) {
ctx := &testContext{T: t, tmpdir: tmpdir, status: s}
- testBadClient(ctx, testcase.backend, testcase.toclose)
+
+ backend := testcase.backend
+
+ limits := nslcd_server.Limits{
+ Timeout: 1 * time.Second,
+ }
+
+ evReload := make(chan bool)
+
+ notifyHandler := func() func(dat []byte, oob []byte) error {
+ reloading := false
+ return func(dat []byte, oob []byte) error {
+ for _, line := range strings.Split(string(dat), "\n") {
+ switch line {
+ case "RELOADING=1":
+ reloading = true
+ case "READY=1":
+ if reloading {
+ evReload <- true
+ }
+ reloading = false
+ }
+ }
+ return nil
+ }
+ }()
+
+ client := func(sockname string) {
+ errfatal := func(err error) {
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ ctx.status <- "talking with server"
+ conn, err := net.Dial("unix", sockname)
+ errfatal(err)
+ errfatal(nslcd_proto.Write(conn, nslcd_proto.NSLCD_VERSION))
+ errfatal(nslcd_proto.Write(conn, nslcd_proto.NSLCD_ACTION_PASSWD_ALL))
+ // Wait for NSLCD_RESULT_*, to make sure the server has made
+ // it in to backend code.
+ var n int32
+ errfatal(nslcd_proto.Read(conn, &n))
+ if n != nslcd_proto.NSLCD_VERSION {
+ ctx.Fatal("server version wrong")
+ }
+ errfatal(nslcd_proto.Read(conn, &n))
+ if n != nslcd_proto.NSLCD_ACTION_PASSWD_ALL {
+ ctx.Fatal("server action wrong")
+ }
+ errfatal(nslcd_proto.Read(conn, &n))
+ if n != nslcd_proto.NSLCD_RESULT_BEGIN && n != nslcd_proto.NSLCD_RESULT_END {
+ ctx.Fatal("server result malformed")
+ }
+ if testcase.toclose {
+ errfatal(conn.Close())
+ }
+
+ ctx.status <- "waiting for server reload"
+ errfatal(unix.Kill(unix.Getpid(), unix.SIGHUP))
+ <-evReload
+ }
+
+ testDriver(ctx, backend, limits, notifyHandler, client)
})
})
}()