Improve testing of Start/Stop/Restart

This commit is contained in:
Lawrence Woodman
2016-07-12 05:45:16 +01:00
parent ced353941e
commit 57c4b2b572
2 changed files with 140 additions and 34 deletions
+131 -21
View File
@@ -8,61 +8,171 @@
package service_test package service_test
import ( import (
"fmt"
"io/ioutil"
"log" "log"
"os" "os"
"path/filepath"
"regexp"
"testing" "testing"
"time"
"github.com/kardianos/service" "github.com/kardianos/service"
) )
const runAsServiceArg = "RunThisAsService"
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
if len(os.Args) > 1 && os.Args[1] == runAsServiceArg { if len(os.Args) == 2 {
runService()
return
}
os.Exit(m.Run()) os.Exit(m.Run())
} else if len(os.Args) == 4 && os.Args[2] == runAsServiceArg {
reportDir := os.Args[3]
writeReport(reportDir, "call")
runService()
writeReport(reportDir, "finished")
os.Exit(0)
}
log.Fatalf("Invalid arguments: %v", os.Args)
} }
func TestInstallRunRestartStopRemove(t *testing.T) { func TestInstallRunRestartStopRemove(t *testing.T) {
p := &program{} p := &program{}
s, err := service.New(p, sc) reportDir := mustTempDir(t)
if err != nil { defer os.RemoveAll(reportDir)
t.Fatal(err)
} s := mustNewRunAsService(t, p, reportDir)
_ = s.Uninstall() _ = s.Uninstall()
err = s.Install() if err := s.Install(); err != nil {
if err != nil { t.Fatal("Install", err)
t.Fatal("install", err)
} }
defer s.Uninstall() defer s.Uninstall()
err = s.Start() if err := s.Start(); err != nil {
if err != nil { t.Fatal("Start", err)
t.Fatal("start", err)
} }
err = s.Restart() defer s.Stop()
if err != nil { checkReport(t, reportDir, "Start()", 1, 0)
if err := s.Restart(); err != nil {
t.Fatal("restart", err) t.Fatal("restart", err)
} }
err = s.Stop()
if err != nil { checkReport(t, reportDir, "Restart()", 2, 1)
p.numStopped = 0
if err := s.Stop(); err != nil {
t.Fatal("stop", err) t.Fatal("stop", err)
} }
err = s.Uninstall() checkReport(t, reportDir, "Stop()", 2, 2)
if err != nil {
if err := s.Uninstall(); err != nil {
t.Fatal("uninstall", err) t.Fatal("uninstall", err)
} }
} }
func runService() { func runService() {
p := &program{} p := &program{}
sc := &service.Config{
Name: "go_service_test",
}
s, err := service.New(p, sc) s, err := service.New(p, sc)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
err = s.Run() if err = s.Run(); err != nil {
log.Fatal(err)
}
}
func mustTempDir(t *testing.T) string {
dir, err := ioutil.TempDir("", "servicetest")
if err != nil {
t.Fatal(err)
}
return dir
}
func writeReport(reportDir string, action string) {
b := []byte("go_test_service_report")
timeStamp := time.Now().UnixNano()
err := ioutil.WriteFile(
filepath.Join(reportDir, fmt.Sprintf("%d-%s", timeStamp, action)),
b,
0644,
)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
} }
var matchActionRegexp = regexp.MustCompile("^(\\d+-)([a-z]*)$")
func getReport(
t *testing.T,
reportDir string,
) (numCalls int, numFinished int) {
numCalls = 0
numFinished = 0
files, err := ioutil.ReadDir(reportDir)
if err != nil {
t.Fatalf("ReadDir(%s) err: %s", reportDir, err)
}
for _, file := range files {
if matchActionRegexp.MatchString(file.Name()) {
action := matchActionRegexp.ReplaceAllString(file.Name(), "$2")
switch action {
case "call":
numCalls++
case "finished":
numFinished++
default:
t.Fatalf("getReport() found report with incorrect action: %s", action)
}
}
}
return
}
func checkReport(
t *testing.T,
reportDir string,
msgPrefix string,
wantNumCalled int,
wantNumFinished int,
) {
var numCalled int
var numFinished int
for i := 0; i < 25; i++ {
numCalled, numFinished = getReport(t, reportDir)
<-time.After(200 * time.Millisecond)
if numCalled == wantNumCalled && numFinished == wantNumFinished {
return
}
}
if numCalled != wantNumCalled {
t.Fatalf("%s - numCalled: %d, want %d",
msgPrefix, numCalled, wantNumCalled)
}
if numFinished != wantNumFinished {
t.Fatalf("%s - numFinished: %d, want %d",
msgPrefix, numFinished, wantNumFinished)
}
}
func mustNewRunAsService(
t *testing.T,
p *program,
reportDir string,
) service.Service {
sc := &service.Config{
Name: "go_service_test",
Arguments: []string{"-test.v=true", runAsServiceArg, reportDir},
}
s, err := service.New(p, sc)
if err != nil {
t.Fatal(err)
}
return s
}
+10 -14
View File
@@ -11,15 +11,11 @@ import (
"github.com/kardianos/service" "github.com/kardianos/service"
) )
const runAsServiceArg = "RunThisAsService"
var sc = &service.Config{
Name: "go_service_test",
Arguments: []string{runAsServiceArg},
}
func TestRunInterrupt(t *testing.T) { func TestRunInterrupt(t *testing.T) {
p := &program{} p := &program{}
sc := &service.Config{
Name: "go_service_test",
}
s, err := service.New(p, sc) s, err := service.New(p, sc)
if err != nil { if err != nil {
t.Fatalf("New err: %s", err) t.Fatalf("New err: %s", err)
@@ -31,9 +27,11 @@ func TestRunInterrupt(t *testing.T) {
}() }()
go func() { go func() {
<-time.After(3 * time.Second) for i := 0; i < 25 && p.numStopped == 0; i++ {
if !p.hasStopped { <-time.After(200 * time.Millisecond)
panic("Run() hasn't been stopped") }
if p.numStopped == 0 {
t.Fatal("Run() hasn't been stopped")
} }
}() }()
@@ -43,8 +41,7 @@ func TestRunInterrupt(t *testing.T) {
} }
type program struct { type program struct {
hasRun bool numStopped int
hasStopped bool
} }
func (p *program) Start(s service.Service) error { func (p *program) Start(s service.Service) error {
@@ -52,10 +49,9 @@ func (p *program) Start(s service.Service) error {
return nil return nil
} }
func (p *program) run() { func (p *program) run() {
p.hasRun = true
// Do work here // Do work here
} }
func (p *program) Stop(s service.Service) error { func (p *program) Stop(s service.Service) error {
p.hasStopped = true p.numStopped++
return nil return nil
} }