diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..9b3f5cc --- /dev/null +++ b/.travis.yml @@ -0,0 +1,16 @@ +language: go +go_import_path: github.com/kardianos/service +sudo: required + +go: + - 1.6 + - tip + +before_install: + - go get github.com/mattn/goveralls + - go get golang.org/x/tools/cmd/cover + +script: + - chmod +x linux-test-su.sh + - sudo ./linux-test-su.sh $GOPATH `which go` + - $GOPATH/bin/goveralls -service=travis-ci diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..92238c3 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,21 @@ +version: "{build}" + +platform: + - x86 + - x64 + +clone_folder: c:\gopath\src\github.com\kardianos\service + +environment: + GOPATH: c:\gopath + +install: + - go version + - go env + - go get -v -t ./... + +build_script: + - go install -v ./... + +test_script: + - go test -v -tags su ./... diff --git a/linux-test-su.sh b/linux-test-su.sh new file mode 100755 index 0000000..3beb240 --- /dev/null +++ b/linux-test-su.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# This script is used to run the tests under linux as root +# +# Usage: +# linux-test-su.sh goPath goBinPath +# +# goPath is the standard GOPATH +# goBinPath is the location of go +# +# Typical usage: +# sudo ./linux-test-su.sh $GOPATH `which go` + +export GOPATH=$1 +export GOROOT=`dirname $(dirname $2)` +$GOROOT/bin/go test -v -tags su ./... diff --git a/name_test.go b/name_test.go index 7f7afe9..3d19915 100644 --- a/name_test.go +++ b/name_test.go @@ -5,9 +5,16 @@ package service import ( + "runtime" + "strings" "testing" ) func TestPlatformName(t *testing.T) { - t.Logf("Platform is %v", Platform()) + got := Platform() + t.Logf("Platform is %v", got) + wantPrefix := runtime.GOOS + "-" + if !strings.HasPrefix(got, wantPrefix) { + t.Errorf("Platform() want: /^%s.*$/, got: %s", wantPrefix, got) + } } diff --git a/service_nosu_test.go b/service_nosu_test.go new file mode 100644 index 0000000..97ee89d --- /dev/null +++ b/service_nosu_test.go @@ -0,0 +1,13 @@ +// Copyright 2016 Lawrence Woodman +// Use of this source code is governed by a zlib-style +// license that can be found in the LICENSE file. + +// +build !su + +package service_test + +import "testing" + +func TestInstallRunRestartStopRemove(t *testing.T) { + t.Skip("skipping test as not running as root/admin (Build tag: su)") +} diff --git a/service_su_test.go b/service_su_test.go new file mode 100644 index 0000000..c537f79 --- /dev/null +++ b/service_su_test.go @@ -0,0 +1,68 @@ +// 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 ( + "log" + "os" + "testing" + + "github.com/kardianos/service" +) + +func TestMain(m *testing.M) { + if len(os.Args) > 1 && os.Args[1] == runAsServiceArg { + runService() + return + } + os.Exit(m.Run()) +} + +func TestInstallRunRestartStopRemove(t *testing.T) { + p := &program{} + s, err := service.New(p, sc) + if err != nil { + t.Fatal(err) + } + _ = s.Uninstall() + + err = s.Install() + if err != nil { + t.Fatal("install", err) + } + defer s.Uninstall() + + err = s.Start() + if err != nil { + t.Fatal("start", err) + } + err = s.Restart() + if err != nil { + t.Fatal("restart", err) + } + err = s.Stop() + if err != nil { + t.Fatal("stop", err) + } + err = s.Uninstall() + if err != nil { + t.Fatal("uninstall", err) + } +} + +func runService() { + p := &program{} + s, err := service.New(p, sc) + if err != nil { + log.Fatal(err) + } + err = s.Run() + if err != nil { + log.Fatal(err) + } +} diff --git a/service_test.go b/service_test.go index 691fd74..8c77d45 100644 --- a/service_test.go +++ b/service_test.go @@ -6,8 +6,8 @@ package service_test import ( "log" - "os" "testing" + "time" "github.com/kardianos/service" ) @@ -19,67 +19,45 @@ var sc = &service.Config{ Arguments: []string{runAsServiceArg}, } -func TestMain(m *testing.M) { - if len(os.Args) > 1 && os.Args[1] == runAsServiceArg { - runService() - return - } - os.Exit(m.Run()) -} - -func TestInstallRunRestartStopRemove(t *testing.T) { - p := &program{} - s, err := service.New(p, sc) - if err != nil { - t.Fatal(err) - } - _ = s.Uninstall() - - err = s.Install() - if err != nil { - t.Fatal("install", err) - } - defer s.Uninstall() - - err = s.Start() - if err != nil { - t.Fatal("start", err) - } - err = s.Restart() - if err != nil { - t.Fatal("restart", err) - } - err = s.Stop() - if err != nil { - t.Fatal("stop", err) - } - err = s.Uninstall() - if err != nil { - t.Fatal("uninstall", err) - } -} - -func runService() { +func TestRunInterrupt(t *testing.T) { p := &program{} s, err := service.New(p, sc) if err != nil { log.Fatal(err) } + + go func() { + <-time.After(1 * time.Second) + interruptProcess(t) + }() + + go func() { + <-time.After(3 * time.Second) + if !p.hasStopped { + panic("Run() hasn't been stopped") + } + }() + err = s.Run() if err != nil { log.Fatal(err) } } -type program struct{} +type program struct { + hasRun bool + hasStopped bool +} func (p *program) Start(s service.Service) error { go p.run() return nil } func (p *program) run() { + p.hasRun = true // Do work here } func (p *program) Stop(s service.Service) error { + p.hasStopped = true return nil } diff --git a/servicetest_unix_test.go b/servicetest_unix_test.go new file mode 100644 index 0000000..1c174d7 --- /dev/null +++ b/servicetest_unix_test.go @@ -0,0 +1,23 @@ +// Copyright 2016 Lawrence Woodman +// Use of this source code is governed by a zlib-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris + +package service_test + +import ( + "os" + "testing" +) + +func interruptProcess(t *testing.T) { + pid := os.Getpid() + p, err := os.FindProcess(pid) + if err != nil { + t.Fatalf("FindProcess: %s", err) + } + if err := p.Signal(os.Interrupt); err != nil { + t.Fatalf("Signal: %s", err) + } +} diff --git a/servicetest_windows_test.go b/servicetest_windows_test.go new file mode 100644 index 0000000..69ffe27 --- /dev/null +++ b/servicetest_windows_test.go @@ -0,0 +1,30 @@ +// Copyright 2016 Lawrence Woodman +// Use of this source code is governed by a zlib-style +// license that can be found in the LICENSE file. + +package service_test + +import ( + "os" + "syscall" + "testing" +) + +func interruptProcess(t *testing.T) { + dll, err := syscall.LoadDLL("kernel32.dll") + if err != nil { + t.Fatalf("LoadDLL(\"kernel32.dll\") err: %s", err) + } + p, err := dll.FindProc("GenerateConsoleCtrlEvent") + if err != nil { + t.Fatalf("FindProc(\"GenerateConsoleCtrlEvent\") err: %s", err) + } + // Send the CTRL_BREAK_EVENT to a console process group that shares + // the console associated with the calling process. + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms683155(v=vs.85).aspx + pid := os.Getpid() + r1, _, err := p.Call(syscall.CTRL_BREAK_EVENT, uintptr(pid)) + if r1 == 0 { + t.Fatalf("Call(CTRL_BREAK_EVENT, %d) err: %s", pid, err) + } +}