Skip to content

Commit

Permalink
supervisor: adding unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
rbeuque74 committed May 11, 2018
1 parent 2325bd3 commit f4fe8c2
Show file tree
Hide file tree
Showing 6 changed files with 294 additions and 10 deletions.
12 changes: 7 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
language: go

sudo: false

go:
- "1.10.x"

before_script:
- go get -t -v ./...
- go get -v github.com/alecthomas/gometalinter/...
- go get -v golang.org/x/tools/cmd/cover
- go get -v github.com/mattn/goveralls
- go get -v -u github.com/kardianos/govendor github.com/alecthomas/gometalinter/... golang.org/x/tools/cmd/cover github.com/mattn/goveralls
- govendor sync -v
# -t is required because some tests have dependency that are not imported from project
- go get -v -t ./...
- gometalinter --install

script:
- go test -timeout 5s -v -covermode=count -coverprofile=coverage.out ./...
- go test -timeout 10s -v -covermode=count -coverprofile=coverage.out ./...
- make
- gometalinter --enable-all --disable=lll

Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ all:
go build -o jagozzi main.go utils.go instance.go

test:
go test -timeout 5s -v ./...
go test -timeout 10s -v ./...
4 changes: 2 additions & 2 deletions plugins/supervisor/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ type pluginConfig struct {
type rawPluginConfig struct {
RawServerURL string `json:"serverurl" default:"unix:///var/run/supervisor.sock"`
RPCNamespace string `json:"rpc_namespace" default:"supervisor"`
RawTimeout *int64 `json:"timeout" default:"5"`
RawTimeout *int64 `json:"timeout" default:"5000"`
}

func loadPluginConfiguration(conf interface{}) (pluginConfig, error) {
Expand All @@ -47,7 +47,7 @@ func loadPluginConfiguration(conf interface{}) (pluginConfig, error) {
}

if cfg.RawTimeout != nil {
cfg.Timeout = time.Duration(*cfg.RawTimeout) * time.Second
cfg.Timeout = time.Duration(*cfg.RawTimeout) * time.Millisecond
}

defaults.SetDefaults(&cfg)
Expand Down
15 changes: 13 additions & 2 deletions plugins/supervisor/supervisor.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ func (c *SupervisorChecker) Run(ctx context.Context) plugins.Result {
rpcc.SetUser(username)
rpcc.SetPassword(password)
}
if c.pluginCfg.Timeout > 0 {
rpcc.SetTimeout(c.pluginCfg.Timeout)
}

processesStates, err := rpcc.GetAllProcessInfo()
if err != nil {
Expand All @@ -64,18 +67,26 @@ func (c *SupervisorChecker) Run(ctx context.Context) plugins.Result {
if pinfo.State != process.RUNNING {
return plugins.Result{
Status: plugins.STATE_CRITICAL,
Message: fmt.Sprintf("Service %s is currently %s: %s", name, processState.String(), description),
Message: fmt.Sprintf("Service %q is currently %s: %s", name, processState.String(), description),
Checker: c,
}
} else if c.cfg.Service != nil {
return plugins.Result{
Status: plugins.STATE_OK,
Message: fmt.Sprintf("Service %s is running: %s", name, description),
Message: fmt.Sprintf("Service %q is running: %s", name, description),
Checker: c,
}
}
}

if c.cfg.Service != nil {
return plugins.Result{
Status: plugins.STATE_CRITICAL,
Message: fmt.Sprintf("Service %q not found", *c.cfg.Service),
Checker: c,
}
}

return plugins.Result{
Status: plugins.STATE_OK,
Message: "All services are running",
Expand Down
257 changes: 257 additions & 0 deletions plugins/supervisor/supervisor_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
package supervisor

import (
"context"
"io/ioutil"
"net"
"os"
"os/exec"
"sync"
"testing"
"time"

"github.com/rbeuque74/jagozzi/plugins"
"github.com/stretchr/testify/assert"
)

const (
supervisordConfig = `[unix_http_server]
file=/tmp/supervisord.sock
[supervisord]
pidfile=/tmp/supervisord.pid
identifier=supervisor
logfile = /tmp/supervisord.log
nodaemon = true
directory = /tmp
nocleanup = false
childlogdir = /tmp
[supervisorctl]
serverurl=unix:///tmp/supervisord.sock
[program:app]
command=/bin/sleep 60
autorestart=true
exitcodes=0,2
stopsignal=TERM
stopwaitsecs=10
directory=/tmp
`
supervisordFaultyConfig = `[unix_http_server]
file=/tmp/supervisord.sock
[supervisord]
pidfile=/tmp/supervisord.pid
identifier=supervisor
logfile = /tmp/supervisord.log
nodaemon = true
directory = /tmp
nocleanup = false
childlogdir = /tmp
[supervisorctl]
serverurl=unix:///tmp/supervisord.sock
[program:app]
command=/bin/false
autorestart=false
exitcodes=10
stopsignal=TERM
stopwaitsecs=10
directory=/tmp
`
)

var pids []*os.Process
var tmpfile *os.File
var mutex sync.Once

func start(t *testing.T, faulty bool) {
var err error
mutex.Do(func() {
cmd := exec.Command("go", "get", "-v", "github.com/ochinchina/supervisord")
if err = cmd.Run(); err != nil {
t.Error(err)
t.FailNow()
}
})

content := []byte(supervisordConfig)
if faulty {
content = []byte(supervisordFaultyConfig)
}
tmpfile, err = ioutil.TempFile("", "supervisord-config")
if err != nil {
t.Error(err)
t.FailNow()
}

if _, err := tmpfile.Write(content); err != nil {
t.Error(err)
t.FailNow()
}
if err := tmpfile.Close(); err != nil {
t.Error(err)
t.FailNow()
}

cmd := exec.Command("supervisord", "-c", tmpfile.Name())
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err = cmd.Start(); err != nil {
t.Error(err)
t.FailNow()
}

pids = append(pids, cmd.Process)
}

func stop(t *testing.T) {
for _, process := range pids {
if process == nil {
t.Error("process pid is nil")
t.FailNow()
}
if err := process.Kill(); err != nil {
t.Error(err)
t.FailNow()
}
}

if tmpfile == nil {
return
}

os.Remove(tmpfile.Name())
os.Remove("/tmp/supervisord.sock")
os.Remove("/tmp/supervisord.log")
os.Remove("/tmp/supervisord.log.0")
os.Remove("/tmp/supervisord.pid")
}

func TestSupervisor(t *testing.T) {
// creating supervisor server
start(t, false)
defer stop(t)

time.Sleep(200 * time.Millisecond)

// creating Command checker
cfg := map[string]interface{}{
"type": "services",
"name": "test-1",
}
pluginCfg := map[string]interface{}{
"serverurl": "unix:///tmp/supervisord.sock",
}

checker, err := NewSupervisorChecker(cfg, pluginCfg)
assert.Nilf(t, err, "command checker instantiation failed: %q", err)

ctxRun, cancelFunc1 := context.WithTimeout(context.Background(), time.Second)
defer cancelFunc1()
result := checker.Run(ctxRun)
assert.Equal(t, plugins.STATE_OK, result.Status)
assert.Equal(t, "All services are running", result.Message)

// service mode
cfg["type"] = "service"
cfg["service"] = "app"

checker, err = NewSupervisorChecker(cfg, pluginCfg)
assert.Nilf(t, err, "command checker instantiation failed: %q", err)

ctxRun, cancelFunc1 = context.WithTimeout(context.Background(), time.Second)
defer cancelFunc1()
result = checker.Run(ctxRun)
assert.Equal(t, plugins.STATE_OK, result.Status)
assert.Contains(t, result.Message, `Service "app" is running: pid `)

// service not found
cfg["type"] = "service"
cfg["service"] = "not-found"

checker, err = NewSupervisorChecker(cfg, pluginCfg)
assert.Nilf(t, err, "command checker instantiation failed: %q", err)

ctxRun, cancelFunc1 = context.WithTimeout(context.Background(), time.Second)
defer cancelFunc1()
result = checker.Run(ctxRun)
assert.Equal(t, plugins.STATE_CRITICAL, result.Status)
assert.Equal(t, `Service "not-found" not found`, result.Message)
}

func TestSupervisorFaulty(t *testing.T) {
// creating supervisor server
start(t, true)
defer stop(t)

// sleeping 2 second to let our supervisor process failing
time.Sleep(2 * time.Second)

// creating Command checker
cfg := map[string]interface{}{
"type": "services",
"name": "test-1",
}
pluginCfg := map[string]interface{}{
"serverurl": "unix:///tmp/supervisord.sock",
}

checker, err := NewSupervisorChecker(cfg, pluginCfg)
assert.Nilf(t, err, "command checker instantiation failed: %q", err)

ctxRun, cancelFunc1 := context.WithTimeout(context.Background(), time.Second)
defer cancelFunc1()
result := checker.Run(ctxRun)
assert.Equal(t, plugins.STATE_CRITICAL, result.Status)
assert.Contains(t, result.Message, `Service "app" is currently EXITED:`)

// service mode
cfg["type"] = "service"
cfg["service"] = "app"

checker, err = NewSupervisorChecker(cfg, pluginCfg)
assert.Nilf(t, err, "command checker instantiation failed: %q", err)

ctxRun, cancelFunc1 = context.WithTimeout(context.Background(), time.Second)
defer cancelFunc1()
result = checker.Run(ctxRun)
assert.Equal(t, plugins.STATE_CRITICAL, result.Status)
assert.Contains(t, result.Message, `Service "app" is currently EXITED:`)
}

func TestSupervisorNotRunning(t *testing.T) {
// creating Command checker
cfg := map[string]interface{}{
"type": "services",
"name": "test-1",
}
pluginCfg := map[string]interface{}{
"serverurl": "unix:///tmp/supervisord.sock",
"timeout": 100,
}

checker, err := NewSupervisorChecker(cfg, pluginCfg)
assert.Nilf(t, err, "command checker instantiation failed: %q", err)

ctxRun, cancelFunc1 := context.WithTimeout(context.Background(), time.Second)
defer cancelFunc1()
result := checker.Run(ctxRun)
assert.Equal(t, plugins.STATE_CRITICAL, result.Status)
assert.Equal(t, "unable to contact supervisor daemon: dial unix /tmp/supervisord.sock: connect: no such file or directory", result.Message)

l, err := net.Listen("unix", "/tmp/supervisord.sock")
if err != nil {
t.Error(err)
t.FailNow()
}
defer l.Close()

ctxRun, cancelFunc1 = context.WithTimeout(context.Background(), time.Second)
defer cancelFunc1()
result = checker.Run(ctxRun)
assert.Equal(t, plugins.STATE_CRITICAL, result.Status)
assert.Equal(t, "unable to contact supervisor daemon: read unix @->/tmp/supervisord.sock: i/o timeout", result.Message)
}
14 changes: 14 additions & 0 deletions vendor/vendor.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"comment": "",
"ignore": "test",
"package": [
{
"checksumSHA1": "5CIl0cy1+8iBQVAE2modrrXQm44=",
"origin": "github.com/rbeuque74/supervisord/xmlrpcclient",
"path": "github.com/ochinchina/supervisord/xmlrpcclient",
"revision": "17328719ae83e63f5b0be05ce27c946d0644f2bc",
"revisionTime": "2018-05-11T11:25:44Z"
}
],
"rootPath": "github.com/rbeuque74/jagozzi"
}

0 comments on commit f4fe8c2

Please sign in to comment.