mirror of
https://github.com/golang/sys.git
synced 2026-02-09 12:16:04 +03:00
CL 244958 includes isWindowsService function that determines if a process is running as a service. The code of the function is based on public .Net implementation. IsAnInteractiveSession function implements similar functionality, but is based on an old Stackoverflow post., which is not as authoritative as code written by Microsoft for their official product. This change copies CL 244958 isWindowsService function into svc package and makes it public. The intention is that future users will prefer IsWindowsService to IsAnInteractiveSession. Also this change adds "Deprecated" comment to IsAnInteractiveSession to point future users to IsWindowsService. Call to IsAnInteractiveSession is also replaced with IsWindowsService in golang.org/x/sys/windows/svc/example package. Change-Id: I4a33b7f590ee8161d1134d8e83668e9da4e6b434 Reviewed-on: https://go-review.googlesource.com/c/sys/+/259397 Run-TryBot: Alex Brainman <alex.brainman@gmail.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org> Trust: Brad Fitzpatrick <bradfitz@golang.org> Trust: Alex Brainman <alex.brainman@gmail.com>
155 lines
3.6 KiB
Go
155 lines
3.6 KiB
Go
// Copyright 2012 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// +build windows
|
|
|
|
package svc_test
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"math/rand"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"golang.org/x/sys/windows/svc"
|
|
"golang.org/x/sys/windows/svc/mgr"
|
|
)
|
|
|
|
func getState(t *testing.T, s *mgr.Service) svc.State {
|
|
status, err := s.Query()
|
|
if err != nil {
|
|
t.Fatalf("Query(%s) failed: %s", s.Name, err)
|
|
}
|
|
return status.State
|
|
}
|
|
|
|
func testState(t *testing.T, s *mgr.Service, want svc.State) {
|
|
have := getState(t, s)
|
|
if have != want {
|
|
t.Fatalf("%s state is=%d want=%d", s.Name, have, want)
|
|
}
|
|
}
|
|
|
|
func waitState(t *testing.T, s *mgr.Service, want svc.State) {
|
|
for i := 0; ; i++ {
|
|
have := getState(t, s)
|
|
if have == want {
|
|
return
|
|
}
|
|
if i > 10 {
|
|
t.Fatalf("%s state is=%d, waiting timeout", s.Name, have)
|
|
}
|
|
time.Sleep(300 * time.Millisecond)
|
|
}
|
|
}
|
|
|
|
func TestExample(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping test in short mode - it modifies system services")
|
|
}
|
|
|
|
const name = "myservice"
|
|
|
|
m, err := mgr.Connect()
|
|
if err != nil {
|
|
t.Fatalf("SCM connection failed: %s", err)
|
|
}
|
|
defer m.Disconnect()
|
|
|
|
dir, err := ioutil.TempDir("", "svc")
|
|
if err != nil {
|
|
t.Fatalf("failed to create temp directory: %v", err)
|
|
}
|
|
defer os.RemoveAll(dir)
|
|
|
|
exepath := filepath.Join(dir, "a.exe")
|
|
o, err := exec.Command("go", "build", "-o", exepath, "golang.org/x/sys/windows/svc/example").CombinedOutput()
|
|
if err != nil {
|
|
t.Fatalf("failed to build service program: %v\n%v", err, string(o))
|
|
}
|
|
|
|
s, err := m.OpenService(name)
|
|
if err == nil {
|
|
err = s.Delete()
|
|
if err != nil {
|
|
s.Close()
|
|
t.Fatalf("Delete failed: %s", err)
|
|
}
|
|
s.Close()
|
|
}
|
|
s, err = m.CreateService(name, exepath, mgr.Config{DisplayName: "my service"}, "is", "auto-started")
|
|
if err != nil {
|
|
t.Fatalf("CreateService(%s) failed: %v", name, err)
|
|
}
|
|
defer s.Close()
|
|
|
|
args := []string{"is", "manual-started", fmt.Sprintf("%d", rand.Int())}
|
|
|
|
testState(t, s, svc.Stopped)
|
|
err = s.Start(args...)
|
|
if err != nil {
|
|
t.Fatalf("Start(%s) failed: %s", s.Name, err)
|
|
}
|
|
waitState(t, s, svc.Running)
|
|
time.Sleep(1 * time.Second)
|
|
|
|
// testing deadlock from issues 4.
|
|
_, err = s.Control(svc.Interrogate)
|
|
if err != nil {
|
|
t.Fatalf("Control(%s) failed: %s", s.Name, err)
|
|
}
|
|
_, err = s.Control(svc.Interrogate)
|
|
if err != nil {
|
|
t.Fatalf("Control(%s) failed: %s", s.Name, err)
|
|
}
|
|
time.Sleep(1 * time.Second)
|
|
|
|
_, err = s.Control(svc.Stop)
|
|
if err != nil {
|
|
t.Fatalf("Control(%s) failed: %s", s.Name, err)
|
|
}
|
|
waitState(t, s, svc.Stopped)
|
|
|
|
err = s.Delete()
|
|
if err != nil {
|
|
t.Fatalf("Delete failed: %s", err)
|
|
}
|
|
|
|
out, err := exec.Command("wevtutil.exe", "qe", "Application", "/q:*[System[Provider[@Name='myservice']]]", "/rd:true", "/c:10").CombinedOutput()
|
|
if err != nil {
|
|
t.Fatalf("wevtutil failed: %v\n%v", err, string(out))
|
|
}
|
|
want := strings.Join(append([]string{name}, args...), "-")
|
|
// Test context passing (see servicemain in sys_386.s and sys_amd64.s).
|
|
want += "-123456"
|
|
if !strings.Contains(string(out), want) {
|
|
t.Errorf("%q string does not contain %q", string(out), want)
|
|
}
|
|
}
|
|
|
|
func TestIsAnInteractiveSession(t *testing.T) {
|
|
isInteractive, err := svc.IsAnInteractiveSession()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !isInteractive {
|
|
t.Error("IsAnInteractiveSession retuns false when running interactively.")
|
|
}
|
|
}
|
|
|
|
func TestIsWindowsService(t *testing.T) {
|
|
isSvc, err := svc.IsWindowsService()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if isSvc {
|
|
t.Error("IsWindowsService retuns true when not running in a service.")
|
|
}
|
|
}
|