Working test
This commit is contained in:
parent
05fe1d1fa6
commit
819c47186c
|
@ -1,6 +1,9 @@
|
|||
runsvinit
|
||||
runsvinit-*-*
|
||||
examples/runsvinit-linux-amd64*
|
||||
zombietest/zombie
|
||||
zombietest/runsvinit
|
||||
*.uptodate
|
||||
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
|
|
45
main.go
45
main.go
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
@ -13,6 +14,9 @@ import (
|
|||
const etcService = "/etc/service"
|
||||
|
||||
func main() {
|
||||
reap := flag.Bool("reap", true, "reap orphan children")
|
||||
flag.Parse()
|
||||
|
||||
log.SetFlags(0)
|
||||
|
||||
runsvdir, err := exec.LookPath("runsvdir")
|
||||
|
@ -35,7 +39,12 @@ func main() {
|
|||
log.Printf("warning: I'm not PID 1, I'm PID %d", pid)
|
||||
}
|
||||
|
||||
go reapAll()
|
||||
if *reap {
|
||||
log.Print("reaping zombies")
|
||||
go reapLoop()
|
||||
} else {
|
||||
log.Print("NOT reaping zombies")
|
||||
}
|
||||
|
||||
supervisor := cmd(runsvdir, etcService)
|
||||
if err := supervisor.Start(); err != nil {
|
||||
|
@ -53,31 +62,33 @@ func main() {
|
|||
}
|
||||
}
|
||||
|
||||
func reapAll() {
|
||||
// From https://github.com/ramr/go-reaper/blob/master/reaper.go
|
||||
func reapLoop() {
|
||||
c := make(chan os.Signal)
|
||||
signal.Notify(c, syscall.SIGCHLD)
|
||||
for range c {
|
||||
go reapOne()
|
||||
reapChildren()
|
||||
}
|
||||
}
|
||||
|
||||
// From https://github.com/ramr/go-reaper/blob/master/reaper.go
|
||||
func reapOne() {
|
||||
var (
|
||||
ws syscall.WaitStatus
|
||||
pid int
|
||||
err error
|
||||
)
|
||||
func reapChildren() {
|
||||
for {
|
||||
pid, err = syscall.Wait4(-1, &ws, 0, nil)
|
||||
if err != syscall.EINTR {
|
||||
break
|
||||
var (
|
||||
ws syscall.WaitStatus
|
||||
pid int
|
||||
err error
|
||||
)
|
||||
for {
|
||||
pid, err = syscall.Wait4(-1, &ws, 0, nil)
|
||||
if err != syscall.EINTR {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err == syscall.ECHILD {
|
||||
return // done
|
||||
}
|
||||
log.Printf("reaped child process %d (%+v)", pid, ws)
|
||||
}
|
||||
if err == syscall.ECHILD {
|
||||
return
|
||||
}
|
||||
log.Printf("reaped child process %d (%+v)", pid, ws)
|
||||
}
|
||||
|
||||
type signaler interface {
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
FROM alpine:latest
|
||||
RUN echo "http://dl-4.alpinelinux.org/alpine/edge/testing" >>/etc/apk/repositories && \
|
||||
apk add --update runit && \
|
||||
rm -rf /var/cache/apk/*
|
||||
|
||||
COPY zombie /
|
||||
RUN mkdir -p /etc/service/zombie
|
||||
COPY run-zombie /etc/service/zombie/run
|
||||
|
||||
COPY /runsvinit /
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
.PHONY: test clean
|
||||
|
||||
test: .test.uptodate
|
||||
./test.bash
|
||||
|
||||
.test.uptodate: runsvinit zombie run-zombie Dockerfile
|
||||
docker build -t zombietest .
|
||||
touch $@
|
||||
|
||||
runsvinit: ../*.go
|
||||
env GOOS=linux GOARCH=amd64 go build -o $@ github.com/peterbourgon/runsvinit
|
||||
|
||||
zombie: .build.uptodate
|
||||
docker run --rm -v $(shell pwd):/mount zombietest-build cc -Wall -Werror -o /mount/zombie /zombie.c
|
||||
|
||||
.build.uptodate: build/zombie.c build/Dockerfile
|
||||
docker build -t zombietest-build build/
|
||||
touch $@
|
||||
|
||||
clean:
|
||||
rm -rf .test.uptodate .build.uptodate runsvinit zombie
|
||||
docker stop zombietest zombietest-build >/dev/null 2>&1 || true
|
||||
docker rm zombietest zombietest-build >/dev/null 2>&1 || true
|
|
@ -0,0 +1,24 @@
|
|||
# zombietest
|
||||
|
||||
This directory contains an integration test to prove runsvinit is actually
|
||||
reaping zombies. `make` builds and executes the test as follows:
|
||||
|
||||
1. We produce a linux/amd64 runsvinit binary by setting GOOS/GOARCH and
|
||||
invoking the Go compiler. Requires Go 1.5, or Go 1.4 built with the
|
||||
appropriate cross-compile options.
|
||||
|
||||
2. The build/zombie.c program spawns five zombies and exits. We compile it for
|
||||
linux/amd64 via a zombietest-build container. We do this so `make` works
|
||||
from a Mac. This requires a working Docker installation.
|
||||
|
||||
3. Once we have linux/amd64 runsvinit and zombie binaries, we produce a
|
||||
zombietest container via the Dockerfile. That container contains a single
|
||||
runit service, /etc/service/zombie, which supervises the zombie binary. We
|
||||
provide no default ENTRYPOINT, so we can supply it at runtime.
|
||||
|
||||
4. Once the zombietest container is built, we invoke the test.bash script.
|
||||
That launches a version of the container with runsvinit set to NOT reap
|
||||
zombies, and after 1 second, verifies that zombies exist. Then, it launches
|
||||
a version of the container with runsvinit set to reap zombies, and after 1
|
||||
second, verifies that no zombies exist.
|
||||
|
|
@ -1,9 +1,3 @@
|
|||
FROM golang:1.5.1
|
||||
|
||||
COPY ../../*.go /go/src/github.com/peterbourgon/runsvinit
|
||||
RUN go install -v github.com/peterbourgon/runsvinit
|
||||
RUN mv /go/bin/runsvinit /mount/
|
||||
|
||||
FROM alpine:latest
|
||||
RUN apk add --update gcc musl-dev && rm -rf /var/cache/apk/*
|
||||
COPY zombie.c /
|
||||
RUN cc -Wall -Werror -o /zombie /zombie.c
|
||||
RUN mv /zombie /mount/
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
.PHONY: all
|
||||
all: zombie runsvinit
|
||||
|
||||
zombie runsvinit: .uptodate
|
||||
docker run -ti --rm -v $(shell pwd):/mount zombie-build
|
||||
|
||||
.uptodate: Dockerfile ../../*.go
|
||||
docker build -t zombie-build .
|
||||
touch $@
|
|
@ -1,18 +1,18 @@
|
|||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main ()
|
||||
{
|
||||
pid_t child_pid;
|
||||
|
||||
child_pid = fork ();
|
||||
if (child_pid > 0) {
|
||||
sleep (60);
|
||||
}
|
||||
else {
|
||||
exit (0);
|
||||
}
|
||||
return 0;
|
||||
int main() {
|
||||
pid_t pid;
|
||||
int i;
|
||||
for (i = 0; i<5; i++) {
|
||||
pid = fork();
|
||||
if (pid > 0) {
|
||||
printf("Zombie #%d born\n", i + 1);
|
||||
} else {
|
||||
printf("Brains...\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
|
||||
exec /zombie
|
|
@ -0,0 +1,34 @@
|
|||
#!/bin/bash
|
||||
|
||||
RC=0
|
||||
SLEEP=1
|
||||
|
||||
C=$(docker run -d zombietest /runsvinit -reap=false)
|
||||
sleep $SLEEP
|
||||
NOREAP=$(docker exec $C ps -o pid,stat | grep Z | wc -l)
|
||||
echo -n without reaping, we have $NOREAP zombies...
|
||||
if [ "$NOREAP" -le "0" ]
|
||||
then
|
||||
echo " FAIL"
|
||||
RC=1
|
||||
else
|
||||
echo " good"
|
||||
fi
|
||||
docker stop $C >/dev/null
|
||||
docker rm $C >/dev/null
|
||||
|
||||
C=$(docker run -d zombietest /runsvinit)
|
||||
sleep $SLEEP
|
||||
YESREAP=$(docker exec $C ps -o pid,stat | grep Z | wc -l)
|
||||
echo -n with reaping, we have $YESREAP zombies...
|
||||
if [ "$YESREAP" -gt "0" ]
|
||||
then
|
||||
echo " FAIL"
|
||||
RC=1
|
||||
else
|
||||
echo " good"
|
||||
fi
|
||||
docker stop $C >/dev/null
|
||||
docker rm $C >/dev/null
|
||||
|
||||
exit $RC
|
Loading…
Reference in New Issue