github.com/go-xe2/third@v1.0.3/golang.org/x/sys/windows/svc/mgr/mgr_test.go (about)

     1  // Copyright 2012 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build windows
     6  
     7  package mgr_test
     8  
     9  import (
    10  	"os"
    11  	"path/filepath"
    12  	"sort"
    13  	"strings"
    14  	"syscall"
    15  	"testing"
    16  	"time"
    17  
    18  	"github.com/go-xe2/third/golang.org/x/sys/windows/svc/mgr"
    19  )
    20  
    21  func TestOpenLanManServer(t *testing.T) {
    22  	m, err := mgr.Connect()
    23  	if err != nil {
    24  		if errno, ok := err.(syscall.Errno); ok && errno == syscall.ERROR_ACCESS_DENIED {
    25  			t.Skip("Skipping test: we don't have rights to manage services.")
    26  		}
    27  		t.Fatalf("SCM connection failed: %s", err)
    28  	}
    29  	defer m.Disconnect()
    30  
    31  	s, err := m.OpenService("LanmanServer")
    32  	if err != nil {
    33  		t.Fatalf("OpenService(lanmanserver) failed: %s", err)
    34  	}
    35  	defer s.Close()
    36  
    37  	_, err = s.Config()
    38  	if err != nil {
    39  		t.Fatalf("Config failed: %s", err)
    40  	}
    41  }
    42  
    43  func install(t *testing.T, m *mgr.Mgr, name, exepath string, c mgr.Config) {
    44  	// Sometimes it takes a while for the service to get
    45  	// removed after previous test run.
    46  	for i := 0; ; i++ {
    47  		s, err := m.OpenService(name)
    48  		if err != nil {
    49  			break
    50  		}
    51  		s.Close()
    52  
    53  		if i > 10 {
    54  			t.Fatalf("service %s already exists", name)
    55  		}
    56  		time.Sleep(300 * time.Millisecond)
    57  	}
    58  
    59  	s, err := m.CreateService(name, exepath, c)
    60  	if err != nil {
    61  		t.Fatalf("CreateService(%s) failed: %v", name, err)
    62  	}
    63  	defer s.Close()
    64  }
    65  
    66  func depString(d []string) string {
    67  	if len(d) == 0 {
    68  		return ""
    69  	}
    70  	for i := range d {
    71  		d[i] = strings.ToLower(d[i])
    72  	}
    73  	ss := sort.StringSlice(d)
    74  	ss.Sort()
    75  	return strings.Join([]string(ss), " ")
    76  }
    77  
    78  func testConfig(t *testing.T, s *mgr.Service, should mgr.Config) mgr.Config {
    79  	is, err := s.Config()
    80  	if err != nil {
    81  		t.Fatalf("Config failed: %s", err)
    82  	}
    83  	if should.DisplayName != is.DisplayName {
    84  		t.Fatalf("config mismatch: DisplayName is %q, but should have %q", is.DisplayName, should.DisplayName)
    85  	}
    86  	if should.StartType != is.StartType {
    87  		t.Fatalf("config mismatch: StartType is %v, but should have %v", is.StartType, should.StartType)
    88  	}
    89  	if should.Description != is.Description {
    90  		t.Fatalf("config mismatch: Description is %q, but should have %q", is.Description, should.Description)
    91  	}
    92  	if depString(should.Dependencies) != depString(is.Dependencies) {
    93  		t.Fatalf("config mismatch: Dependencies is %v, but should have %v", is.Dependencies, should.Dependencies)
    94  	}
    95  	return is
    96  }
    97  
    98  func testRecoveryActions(t *testing.T, s *mgr.Service, should []mgr.RecoveryAction) {
    99  	is, err := s.RecoveryActions()
   100  	if err != nil {
   101  		t.Fatalf("RecoveryActions failed: %s", err)
   102  	}
   103  	if len(should) != len(is) {
   104  		t.Errorf("recovery action mismatch: contains %v actions, but should have %v", len(is), len(should))
   105  	}
   106  	for i, _ := range is {
   107  		if should[i].Type != is[i].Type {
   108  			t.Errorf("recovery action mismatch: Type is %v, but should have %v", is[i].Type, should[i].Type)
   109  		}
   110  		if should[i].Delay != is[i].Delay {
   111  			t.Errorf("recovery action mismatch: Delay is %v, but should have %v", is[i].Delay, should[i].Delay)
   112  		}
   113  	}
   114  }
   115  
   116  func testResetPeriod(t *testing.T, s *mgr.Service, should uint32) {
   117  	is, err := s.ResetPeriod()
   118  	if err != nil {
   119  		t.Fatalf("ResetPeriod failed: %s", err)
   120  	}
   121  	if should != is {
   122  		t.Errorf("reset period mismatch: reset period is %v, but should have %v", is, should)
   123  	}
   124  }
   125  
   126  func testSetRecoveryActions(t *testing.T, s *mgr.Service) {
   127  	r := []mgr.RecoveryAction{
   128  		mgr.RecoveryAction{
   129  			Type:  mgr.NoAction,
   130  			Delay: 60000 * time.Millisecond,
   131  		},
   132  		mgr.RecoveryAction{
   133  			Type:  mgr.ServiceRestart,
   134  			Delay: 4 * time.Minute,
   135  		},
   136  		mgr.RecoveryAction{
   137  			Type:  mgr.ServiceRestart,
   138  			Delay: time.Minute,
   139  		},
   140  		mgr.RecoveryAction{
   141  			Type:  mgr.RunCommand,
   142  			Delay: 4000 * time.Millisecond,
   143  		},
   144  	}
   145  
   146  	// 4 recovery actions with reset period
   147  	err := s.SetRecoveryActions(r, uint32(10000))
   148  	if err != nil {
   149  		t.Fatalf("SetRecoveryActions failed: %v", err)
   150  	}
   151  	testRecoveryActions(t, s, r)
   152  	testResetPeriod(t, s, uint32(10000))
   153  
   154  	// Infinite reset period
   155  	err = s.SetRecoveryActions(r, syscall.INFINITE)
   156  	if err != nil {
   157  		t.Fatalf("SetRecoveryActions failed: %v", err)
   158  	}
   159  	testRecoveryActions(t, s, r)
   160  	testResetPeriod(t, s, syscall.INFINITE)
   161  
   162  	// nil recovery actions
   163  	err = s.SetRecoveryActions(nil, 0)
   164  	if err.Error() != "recoveryActions cannot be nil" {
   165  		t.Fatalf("SetRecoveryActions failed with unexpected error message of %q", err)
   166  	}
   167  
   168  	// Delete all recovery actions and reset period
   169  	err = s.ResetRecoveryActions()
   170  	if err != nil {
   171  		t.Fatalf("ResetRecoveryActions failed: %v", err)
   172  	}
   173  	testRecoveryActions(t, s, nil)
   174  	testResetPeriod(t, s, 0)
   175  }
   176  
   177  func testRebootMessage(t *testing.T, s *mgr.Service, should string) {
   178  	err := s.SetRebootMessage(should)
   179  	if err != nil {
   180  		t.Fatalf("SetRebootMessage failed: %v", err)
   181  	}
   182  	is, err := s.RebootMessage()
   183  	if err != nil {
   184  		t.Fatalf("RebootMessage failed: %v", err)
   185  	}
   186  	if should != is {
   187  		t.Errorf("reboot message mismatch: message is %q, but should have %q", is, should)
   188  	}
   189  }
   190  
   191  func testRecoveryCommand(t *testing.T, s *mgr.Service, should string) {
   192  	err := s.SetRecoveryCommand(should)
   193  	if err != nil {
   194  		t.Fatalf("SetRecoveryCommand failed: %v", err)
   195  	}
   196  	is, err := s.RecoveryCommand()
   197  	if err != nil {
   198  		t.Fatalf("RecoveryCommand failed: %v", err)
   199  	}
   200  	if should != is {
   201  		t.Errorf("recovery command mismatch: command is %q, but should have %q", is, should)
   202  	}
   203  }
   204  
   205  func remove(t *testing.T, s *mgr.Service) {
   206  	err := s.Delete()
   207  	if err != nil {
   208  		t.Fatalf("Delete failed: %s", err)
   209  	}
   210  }
   211  
   212  func TestMyService(t *testing.T) {
   213  	if testing.Short() {
   214  		t.Skip("skipping test in short mode - it modifies system services")
   215  	}
   216  
   217  	const name = "myservice"
   218  
   219  	m, err := mgr.Connect()
   220  	if err != nil {
   221  		if errno, ok := err.(syscall.Errno); ok && errno == syscall.ERROR_ACCESS_DENIED {
   222  			t.Skip("Skipping test: we don't have rights to manage services.")
   223  		}
   224  		t.Fatalf("SCM connection failed: %s", err)
   225  	}
   226  	defer m.Disconnect()
   227  
   228  	c := mgr.Config{
   229  		StartType:    mgr.StartDisabled,
   230  		DisplayName:  "my service",
   231  		Description:  "my service is just a test",
   232  		Dependencies: []string{"LanmanServer", "W32Time"},
   233  	}
   234  
   235  	exename := os.Args[0]
   236  	exepath, err := filepath.Abs(exename)
   237  	if err != nil {
   238  		t.Fatalf("filepath.Abs(%s) failed: %s", exename, err)
   239  	}
   240  
   241  	install(t, m, name, exepath, c)
   242  
   243  	s, err := m.OpenService(name)
   244  	if err != nil {
   245  		t.Fatalf("service %s is not installed", name)
   246  	}
   247  	defer s.Close()
   248  
   249  	c.BinaryPathName = exepath
   250  	c = testConfig(t, s, c)
   251  
   252  	c.StartType = mgr.StartManual
   253  	err = s.UpdateConfig(c)
   254  	if err != nil {
   255  		t.Fatalf("UpdateConfig failed: %v", err)
   256  	}
   257  
   258  	testConfig(t, s, c)
   259  
   260  	svcnames, err := m.ListServices()
   261  	if err != nil {
   262  		t.Fatalf("ListServices failed: %v", err)
   263  	}
   264  	var myserviceIsInstalled bool
   265  	for _, sn := range svcnames {
   266  		if sn == name {
   267  			myserviceIsInstalled = true
   268  			break
   269  		}
   270  	}
   271  	if !myserviceIsInstalled {
   272  		t.Errorf("ListServices failed to find %q service", name)
   273  	}
   274  
   275  	testSetRecoveryActions(t, s)
   276  	testRebootMessage(t, s, "myservice failed")
   277  	testRebootMessage(t, s, "") // delete reboot message
   278  	testRecoveryCommand(t, s, "sc query myservice")
   279  	testRecoveryCommand(t, s, "") // delete recovery command
   280  
   281  	remove(t, s)
   282  }