179 lines
3.5 KiB
Go
179 lines
3.5 KiB
Go
// Copyright 2015 Daniel Theophanes.
|
|
// Use of this source code is governed by a zlib-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// This needs to be run as root/admin hence the reason there is a build tag
|
|
// +build su
|
|
|
|
package service_test
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/kardianos/service"
|
|
)
|
|
|
|
const runAsServiceArg = "RunThisAsService"
|
|
|
|
func TestMain(m *testing.M) {
|
|
if len(os.Args) == 2 {
|
|
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) {
|
|
p := &program{}
|
|
reportDir := mustTempDir(t)
|
|
defer os.RemoveAll(reportDir)
|
|
|
|
s := mustNewRunAsService(t, p, reportDir)
|
|
_ = s.Uninstall()
|
|
|
|
if err := s.Install(); err != nil {
|
|
t.Fatal("Install", err)
|
|
}
|
|
defer s.Uninstall()
|
|
|
|
if err := s.Start(); err != nil {
|
|
t.Fatal("Start", err)
|
|
}
|
|
defer s.Stop()
|
|
checkReport(t, reportDir, "Start()", 1, 0)
|
|
|
|
if err := s.Restart(); err != nil {
|
|
t.Fatal("restart", err)
|
|
}
|
|
|
|
checkReport(t, reportDir, "Restart()", 2, 1)
|
|
p.numStopped = 0
|
|
if err := s.Stop(); err != nil {
|
|
t.Fatal("stop", err)
|
|
}
|
|
checkReport(t, reportDir, "Stop()", 2, 2)
|
|
|
|
if err := s.Uninstall(); err != nil {
|
|
t.Fatal("uninstall", err)
|
|
}
|
|
}
|
|
|
|
func runService() {
|
|
p := &program{}
|
|
sc := &service.Config{
|
|
Name: "go_service_test",
|
|
}
|
|
s, err := service.New(p, sc)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
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 {
|
|
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
|
|
}
|